]> git.saurik.com Git - wxWidgets.git/blame - src/msw/webview_ie.cpp
Allow using '(' and ')' in wxFileConfig entry names unescaped.
[wxWidgets.git] / src / msw / webview_ie.cpp
CommitLineData
61b98a2d 1/////////////////////////////////////////////////////////////////////////////
8290e3cd 2// Name: src/msw/webview_ie.cpp
61b98a2d
SL
3// Purpose: wxMSW wxWebViewIE class implementation for web view component
4// Author: Marianne Gagnon
5// Id: $Id$
153530af 6// Copyright: (c) 2010 Marianne Gagnon, 2011 Steven Lamerton
61b98a2d
SL
7// Licence: wxWindows licence
8/////////////////////////////////////////////////////////////////////////////
9
384b8d9f
SL
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
8290e3cd 17#include "wx/msw/webview_ie.h"
61b98a2d 18
9d2f31db 19#if wxUSE_WEBVIEW && wxUSE_WEBVIEW_IE
61b98a2d
SL
20
21#include <olectl.h>
22#include <oleidl.h>
23#include <exdispid.h>
24#include <exdisp.h>
25#include <mshtml.h>
cd4e4673 26#include "wx/msw/registry.h"
1d7d04d7 27#include "wx/msw/missing.h"
7d3f6b4d 28#include "wx/filesys.h"
e924e848 29#include "wx/dynlib.h"
f559d1a2
VZ
30#include <initguid.h>
31
32/* These GUID definitions are our own implementation to support interfaces
33 * normally in urlmon.h. See include/wx/msw/webview_ie.h
34 */
35
36namespace {
37
38DEFINE_GUID(wxIID_IInternetProtocolRoot,0x79eac9e3,0xbaf9,0x11ce,0x8c,0x82,0,0xaa,0,0x4b,0xa9,0xb);
39DEFINE_GUID(wxIID_IInternetProtocol,0x79eac9e4,0xbaf9,0x11ce,0x8c,0x82,0,0xaa,0,0x4b,0xa9,0xb);
40
41}
7d3f6b4d 42
cddf4541
SL
43wxIMPLEMENT_DYNAMIC_CLASS(wxWebViewIE, wxWebView);
44
61b98a2d 45BEGIN_EVENT_TABLE(wxWebViewIE, wxControl)
97ad1425
SL
46 EVT_ACTIVEX(wxID_ANY, wxWebViewIE::onActiveXEvent)
47 EVT_ERASE_BACKGROUND(wxWebViewIE::onEraseBg)
61b98a2d
SL
48END_EVENT_TABLE()
49
50bool wxWebViewIE::Create(wxWindow* parent,
51 wxWindowID id,
52 const wxString& url,
53 const wxPoint& pos,
54 const wxSize& size,
55 long style,
56 const wxString& name)
57{
58 if (!wxControl::Create(parent, id, pos, size, style,
59 wxDefaultValidator, name))
60 {
61 return false;
62 }
63
64 m_webBrowser = NULL;
61b98a2d 65 m_isBusy = false;
74af0b13
SL
66 m_historyLoadingFromList = false;
67 m_historyEnabled = true;
68 m_historyPosition = -1;
c5f417cb 69 m_zoomType = wxWEB_VIEW_ZOOM_TYPE_TEXT;
61b98a2d
SL
70
71 if (::CoCreateInstance(CLSID_WebBrowser, NULL,
72 CLSCTX_INPROC_SERVER, // CLSCTX_INPROC,
73 IID_IWebBrowser2 , (void**)&m_webBrowser) != 0)
74 {
75 wxLogError("Failed to initialize IE, CoCreateInstance returned an error");
76 return false;
77 }
78
79 m_ie.SetDispatchPtr(m_webBrowser); // wxAutomationObject will release itself
80
81 m_webBrowser->put_RegisterAsBrowser(VARIANT_TRUE);
82 m_webBrowser->put_RegisterAsDropTarget(VARIANT_TRUE);
61b98a2d
SL
83
84 m_container = new wxActiveXContainer(this, IID_IWebBrowser2, m_webBrowser);
85
4d0dddc7 86 LoadURL(url);
61b98a2d
SL
87 return true;
88}
89
39498710
SL
90wxWebViewIE::~wxWebViewIE()
91{
92 for(unsigned int i = 0; i < m_factories.size(); i++)
93 {
94 m_factories[i]->Release();
95 }
96}
61b98a2d 97
4d0dddc7 98void wxWebViewIE::LoadURL(const wxString& url)
61b98a2d 99{
e8d243a9 100 m_ie.CallMethod("Navigate", wxConvertStringToOle(url));
61b98a2d
SL
101}
102
442262d4 103void wxWebViewIE::SetPage(const wxString& html, const wxString& baseUrl)
61b98a2d 104{
7f98bdd6 105 BSTR bstr = SysAllocString(OLESTR(""));
61b98a2d
SL
106 SAFEARRAY *psaStrings = SafeArrayCreateVector(VT_VARIANT, 0, 1);
107 if (psaStrings != NULL)
108 {
109 VARIANT *param;
110 HRESULT hr = SafeArrayAccessData(psaStrings, (LPVOID*)&param);
111 param->vt = VT_BSTR;
112 param->bstrVal = bstr;
442262d4 113
7f98bdd6
SL
114 hr = SafeArrayUnaccessData(psaStrings);
115
617227c3 116 IHTMLDocument2* document = GetDocument();
61b98a2d 117 document->write(psaStrings);
7f98bdd6 118 document->close();
442262d4 119 document->Release();
61b98a2d 120
61b98a2d 121 SafeArrayDestroy(psaStrings);
442262d4 122
7f98bdd6
SL
123 bstr = SysAllocString(html.wc_str());
124
125 // Creates a new one-dimensional array
126 psaStrings = SafeArrayCreateVector(VT_VARIANT, 0, 1);
127 if (psaStrings != NULL)
128 {
129 hr = SafeArrayAccessData(psaStrings, (LPVOID*)&param);
130 param->vt = VT_BSTR;
131 param->bstrVal = bstr;
132 hr = SafeArrayUnaccessData(psaStrings);
133
134 document = GetDocument();
135 document->write(psaStrings);
136 document->Release();
137
138 // SafeArrayDestroy calls SysFreeString for each BSTR
139 SafeArrayDestroy(psaStrings);
140
141 //We send the events when we are done to mimic webkit
142 //Navigated event
143 wxWebViewEvent event(wxEVT_COMMAND_WEB_VIEW_NAVIGATED,
144 GetId(), baseUrl, "");
145 event.SetEventObject(this);
146 HandleWindowEvent(event);
147
148 //Document complete event
149 event.SetEventType(wxEVT_COMMAND_WEB_VIEW_LOADED);
150 event.SetEventObject(this);
151 HandleWindowEvent(event);
152 }
153 else
154 {
155 wxLogError("wxWebViewIE::SetPage() : psaStrings is NULL");
156 }
61b98a2d
SL
157 }
158 else
159 {
7f98bdd6 160 wxLogError("wxWebViewIE::SetPage() : psaStrings is NULL during clear");
61b98a2d 161 }
61b98a2d
SL
162}
163
e669ddde 164wxString wxWebViewIE::GetPageSource() const
61b98a2d 165{
617227c3 166 IHTMLDocument2* document = GetDocument();
61b98a2d
SL
167 IHTMLElement *bodyTag = NULL;
168 IHTMLElement *htmlTag = NULL;
423adfde 169 wxString source;
7fbc727b
SL
170 HRESULT hr = document->get_body(&bodyTag);
171 if(SUCCEEDED(hr))
172 {
173 hr = bodyTag->get_parentElement(&htmlTag);
174 if(SUCCEEDED(hr))
175 {
423adfde 176 BSTR bstr;
7fbc727b 177 htmlTag->get_outerHTML(&bstr);
423adfde 178 source = wxString(bstr);
7fbc727b
SL
179 htmlTag->Release();
180 }
181 bodyTag->Release();
182 }
61b98a2d
SL
183
184 document->Release();
423adfde 185 return source;
61b98a2d
SL
186}
187
e669ddde 188wxWebViewZoom wxWebViewIE::GetZoom() const
61b98a2d 189{
8acbf08b
SL
190 switch( m_zoomType )
191 {
192 case wxWEB_VIEW_ZOOM_TYPE_LAYOUT:
193 return GetIEOpticalZoom();
194 case wxWEB_VIEW_ZOOM_TYPE_TEXT:
195 return GetIETextZoom();
196 default:
197 wxFAIL;
198 }
423adfde
SL
199
200 //Dummy return to stop compiler warnings
201 return wxWEB_VIEW_ZOOM_MEDIUM;
1d7d04d7 202
61b98a2d 203}
c5f417cb 204
61b98a2d
SL
205void wxWebViewIE::SetZoom(wxWebViewZoom zoom)
206{
8acbf08b
SL
207 switch( m_zoomType )
208 {
209 case wxWEB_VIEW_ZOOM_TYPE_LAYOUT:
210 SetIEOpticalZoom(zoom);
211 break;
212 case wxWEB_VIEW_ZOOM_TYPE_TEXT:
213 SetIETextZoom(zoom);
214 break;
215 default:
216 wxFAIL;
217 }
61b98a2d
SL
218}
219
c5f417cb 220void wxWebViewIE::SetIETextZoom(wxWebViewZoom level)
61b98a2d 221{
1d7d04d7 222 //We do not use OLECMDID_OPTICAL_GETZOOMRANGE as the docs say the range
c5f417cb
SL
223 //is 0 to 4 so the check is unnecessary, these match exactly with the
224 //enum values
61b98a2d
SL
225 VARIANT zoomVariant;
226 VariantInit (&zoomVariant);
227 V_VT(&zoomVariant) = VT_I4;
228 V_I4(&zoomVariant) = level;
229
8acbf08b
SL
230#if wxDEBUG_LEVEL
231 HRESULT result =
232#endif
233 m_webBrowser->ExecWB(OLECMDID_ZOOM,
234 OLECMDEXECOPT_DONTPROMPTUSER,
235 &zoomVariant, NULL);
c5f417cb 236 wxASSERT(result == S_OK);
61b98a2d
SL
237}
238
e669ddde 239wxWebViewZoom wxWebViewIE::GetIETextZoom() const
61b98a2d
SL
240{
241 VARIANT zoomVariant;
242 VariantInit (&zoomVariant);
243 V_VT(&zoomVariant) = VT_I4;
61b98a2d 244
8acbf08b
SL
245#if wxDEBUG_LEVEL
246 HRESULT result =
247#endif
248 m_webBrowser->ExecWB(OLECMDID_ZOOM,
249 OLECMDEXECOPT_DONTPROMPTUSER,
250 NULL, &zoomVariant);
c5f417cb 251 wxASSERT(result == S_OK);
61b98a2d 252
c5f417cb
SL
253 //We can safely cast here as we know that the range matches our enum
254 return static_cast<wxWebViewZoom>(V_I4(&zoomVariant));
61b98a2d
SL
255}
256
c5f417cb 257void wxWebViewIE::SetIEOpticalZoom(wxWebViewZoom level)
61b98a2d 258{
1d7d04d7 259 //We do not use OLECMDID_OPTICAL_GETZOOMRANGE as the docs say the range
c5f417cb 260 //is 10 to 1000 so the check is unnecessary
61b98a2d
SL
261 VARIANT zoomVariant;
262 VariantInit (&zoomVariant);
263 V_VT(&zoomVariant) = VT_I4;
c5f417cb
SL
264
265 //We make a somewhat arbitray map here, taken from values used by webkit
266 switch(level)
267 {
268 case wxWEB_VIEW_ZOOM_TINY:
269 V_I4(&zoomVariant) = 60;
270 break;
271 case wxWEB_VIEW_ZOOM_SMALL:
272 V_I4(&zoomVariant) = 80;
273 break;
274 case wxWEB_VIEW_ZOOM_MEDIUM:
275 V_I4(&zoomVariant) = 100;
276 break;
277 case wxWEB_VIEW_ZOOM_LARGE:
278 V_I4(&zoomVariant) = 130;
279 break;
280 case wxWEB_VIEW_ZOOM_LARGEST:
281 V_I4(&zoomVariant) = 160;
282 break;
283 default:
284 wxFAIL;
285 }
61b98a2d 286
8acbf08b
SL
287#if wxDEBUG_LEVEL
288 HRESULT result =
289#endif
290 m_webBrowser->ExecWB((OLECMDID)63 /*OLECMDID_OPTICAL_ZOOM*/,
291 OLECMDEXECOPT_DODEFAULT,
292 &zoomVariant,
293 NULL);
c5f417cb 294 wxASSERT(result == S_OK);
61b98a2d
SL
295}
296
e669ddde 297wxWebViewZoom wxWebViewIE::GetIEOpticalZoom() const
61b98a2d 298{
61b98a2d
SL
299 VARIANT zoomVariant;
300 VariantInit (&zoomVariant);
301 V_VT(&zoomVariant) = VT_I4;
61b98a2d 302
8acbf08b
SL
303#if wxDEBUG_LEVEL
304 HRESULT result =
305#endif
306 m_webBrowser->ExecWB((OLECMDID)63 /*OLECMDID_OPTICAL_ZOOM*/,
307 OLECMDEXECOPT_DODEFAULT, NULL,
308 &zoomVariant);
c5f417cb 309 wxASSERT(result == S_OK);
61b98a2d
SL
310
311 const int zoom = V_I4(&zoomVariant);
61b98a2d 312
c5f417cb
SL
313 //We make a somewhat arbitray map here, taken from values used by webkit
314 if (zoom <= 65)
315 {
316 return wxWEB_VIEW_ZOOM_TINY;
317 }
318 else if (zoom > 65 && zoom <= 90)
319 {
320 return wxWEB_VIEW_ZOOM_SMALL;
321 }
322 else if (zoom > 90 && zoom <= 115)
323 {
324 return wxWEB_VIEW_ZOOM_MEDIUM;
325 }
326 else if (zoom > 115 && zoom <= 145)
327 {
328 return wxWEB_VIEW_ZOOM_LARGE;
329 }
423adfde 330 else /*if (zoom > 145) */ //Using else removes a compiler warning
c5f417cb
SL
331 {
332 return wxWEB_VIEW_ZOOM_LARGEST;
333 }
61b98a2d
SL
334}
335
c5f417cb 336void wxWebViewIE::SetZoomType(wxWebViewZoomType type)
61b98a2d 337{
c5f417cb 338 m_zoomType = type;
61b98a2d
SL
339}
340
341wxWebViewZoomType wxWebViewIE::GetZoomType() const
342{
c5f417cb 343 return m_zoomType;
61b98a2d
SL
344}
345
cd4e4673 346bool wxWebViewIE::CanSetZoomType(wxWebViewZoomType type) const
61b98a2d 347{
cd4e4673
SL
348 //IE 6 and below only support text zoom, so check the registry to see what
349 //version we actually have
350 wxRegKey key(wxRegKey::HKLM, "Software\\Microsoft\\Internet Explorer");
351 wxString value;
352 key.QueryValue("Version", value);
353
354 long version = wxAtoi(value.Left(1));
355 if(version <= 6 && type == wxWEB_VIEW_ZOOM_TYPE_LAYOUT)
356 return false;
357 else
358 return true;
61b98a2d
SL
359}
360
361void wxWebViewIE::Print()
362{
363 m_webBrowser->ExecWB(OLECMDID_PRINTPREVIEW,
364 OLECMDEXECOPT_DODEFAULT, NULL, NULL);
365}
366
e669ddde 367bool wxWebViewIE::CanGoBack() const
61b98a2d 368{
74af0b13
SL
369 if(m_historyEnabled)
370 return m_historyPosition > 0;
371 else
372 return false;
373}
61b98a2d 374
e669ddde 375bool wxWebViewIE::CanGoForward() const
74af0b13
SL
376{
377 if(m_historyEnabled)
22ca10fa 378 return m_historyPosition != static_cast<int>(m_historyList.size()) - 1;
74af0b13
SL
379 else
380 return false;
61b98a2d
SL
381}
382
c13d6ac1 383void wxWebViewIE::LoadHistoryItem(wxSharedPtr<wxWebViewHistoryItem> item)
61b98a2d 384{
74af0b13
SL
385 int pos = -1;
386 for(unsigned int i = 0; i < m_historyList.size(); i++)
387 {
3e7968c2
SL
388 //We compare the actual pointers to find the correct item
389 if(m_historyList[i].get() == item.get())
74af0b13
SL
390 pos = i;
391 }
1d7d04d7 392 wxASSERT_MSG(pos != static_cast<int>(m_historyList.size()),
22ca10fa 393 "invalid history item");
74af0b13 394 m_historyLoadingFromList = true;
4d0dddc7 395 LoadURL(item->GetUrl());
74af0b13
SL
396 m_historyPosition = pos;
397}
61b98a2d 398
c13d6ac1 399wxVector<wxSharedPtr<wxWebViewHistoryItem> > wxWebViewIE::GetBackwardHistory()
5cbda74b 400{
c13d6ac1 401 wxVector<wxSharedPtr<wxWebViewHistoryItem> > backhist;
5cbda74b
SL
402 //As we don't have std::copy or an iterator constructor in the wxwidgets
403 //native vector we construct it by hand
404 for(int i = 0; i < m_historyPosition; i++)
405 {
406 backhist.push_back(m_historyList[i]);
407 }
408 return backhist;
409}
410
c13d6ac1 411wxVector<wxSharedPtr<wxWebViewHistoryItem> > wxWebViewIE::GetForwardHistory()
5cbda74b 412{
c13d6ac1 413 wxVector<wxSharedPtr<wxWebViewHistoryItem> > forwardhist;
5cbda74b
SL
414 //As we don't have std::copy or an iterator constructor in the wxwidgets
415 //native vector we construct it by hand
22ca10fa 416 for(int i = m_historyPosition + 1; i < static_cast<int>(m_historyList.size()); i++)
5cbda74b
SL
417 {
418 forwardhist.push_back(m_historyList[i]);
419 }
420 return forwardhist;
421}
422
74af0b13
SL
423void wxWebViewIE::GoBack()
424{
3e7968c2 425 LoadHistoryItem(m_historyList[m_historyPosition - 1]);
74af0b13
SL
426}
427
428void wxWebViewIE::GoForward()
429{
3e7968c2 430 LoadHistoryItem(m_historyList[m_historyPosition + 1]);
61b98a2d
SL
431}
432
433void wxWebViewIE::Stop()
434{
7fbc727b 435 m_ie.CallMethod("Stop");
61b98a2d
SL
436}
437
74af0b13
SL
438void wxWebViewIE::ClearHistory()
439{
440 m_historyList.clear();
441 m_historyPosition = -1;
442}
443
444void wxWebViewIE::EnableHistory(bool enable)
445{
446 m_historyEnabled = enable;
447 m_historyList.clear();
448 m_historyPosition = -1;
449}
61b98a2d
SL
450
451void wxWebViewIE::Reload(wxWebViewReloadFlags flags)
452{
7aa18fc7
SL
453 VARIANTARG level;
454 VariantInit(&level);
455 V_VT(&level) = VT_I2;
61b98a2d 456
7aa18fc7 457 switch(flags)
61b98a2d 458 {
7aa18fc7
SL
459 case wxWEB_VIEW_RELOAD_DEFAULT:
460 V_I2(&level) = REFRESH_NORMAL;
461 break;
462 case wxWEB_VIEW_RELOAD_NO_CACHE:
463 V_I2(&level) = REFRESH_COMPLETELY;
464 break;
465 default:
466 wxFAIL_MSG("Unexpected reload type");
61b98a2d
SL
467 }
468
7aa18fc7 469 m_webBrowser->Refresh2(&level);
61b98a2d
SL
470}
471
472bool wxWebViewIE::IsOfflineMode()
473{
474 wxVariant out = m_ie.GetProperty("Offline");
475
476 wxASSERT(out.GetType() == "bool");
477
478 return out.GetBool();
479}
480
481void wxWebViewIE::SetOfflineMode(bool offline)
482{
483 // FIXME: the wxWidgets docs do not really document what the return
484 // parameter of PutProperty is
8acbf08b
SL
485#if wxDEBUG_LEVEL
486 const bool success =
487#endif
488 m_ie.PutProperty("Offline", (offline ?
489 VARIANT_TRUE :
490 VARIANT_FALSE));
61b98a2d
SL
491 wxASSERT(success);
492}
493
e669ddde 494bool wxWebViewIE::IsBusy() const
60eabdbe 495{
61b98a2d
SL
496 if (m_isBusy) return true;
497
498 wxVariant out = m_ie.GetProperty("Busy");
499
500 wxASSERT(out.GetType() == "bool");
501
502 return out.GetBool();
503}
504
e669ddde 505wxString wxWebViewIE::GetCurrentURL() const
61b98a2d
SL
506{
507 wxVariant out = m_ie.GetProperty("LocationURL");
508
509 wxASSERT(out.GetType() == "string");
510 return out.GetString();
511}
512
e669ddde 513wxString wxWebViewIE::GetCurrentTitle() const
61b98a2d 514{
617227c3 515 IHTMLDocument2* document = GetDocument();
977c5320 516 BSTR title;
7fbc727b 517
977c5320 518 document->get_nameProp(&title);
7fbc727b 519 document->Release();
977c5320 520 return wxString(title);
61b98a2d
SL
521}
522
e669ddde 523bool wxWebViewIE::CanCut() const
4681a3ea
SL
524{
525 return CanExecCommand("Cut");
526}
527
e669ddde 528bool wxWebViewIE::CanCopy() const
4681a3ea
SL
529{
530 return CanExecCommand("Copy");
531}
e669ddde 532bool wxWebViewIE::CanPaste() const
4681a3ea
SL
533{
534 return CanExecCommand("Paste");
535}
536
537void wxWebViewIE::Cut()
538{
539 ExecCommand("Cut");
540}
541
542void wxWebViewIE::Copy()
543{
544 ExecCommand("Copy");
545}
546
547void wxWebViewIE::Paste()
548{
549 ExecCommand("Paste");
550}
551
e669ddde 552bool wxWebViewIE::CanUndo() const
97e49559
SL
553{
554 return CanExecCommand("Undo");
555}
e669ddde 556bool wxWebViewIE::CanRedo() const
97e49559
SL
557{
558 return CanExecCommand("Redo");
559}
560
561void wxWebViewIE::Undo()
562{
563 ExecCommand("Undo");
564}
565
566void wxWebViewIE::Redo()
567{
568 ExecCommand("Redo");
569}
570
c7cbe308
SL
571void wxWebViewIE::SetEditable(bool enable)
572{
573 IHTMLDocument2* document = GetDocument();
574 if( enable )
575 document->put_designMode(SysAllocString(L"On"));
576 else
577 document->put_designMode(SysAllocString(L"Off"));
7fbc727b
SL
578
579 document->Release();
c7cbe308
SL
580}
581
e669ddde 582bool wxWebViewIE::IsEditable() const
c7cbe308
SL
583{
584 IHTMLDocument2* document = GetDocument();
585 BSTR mode;
586 document->get_designMode(&mode);
423adfde 587 document->Release();
c7cbe308
SL
588 if(wxString(mode) == "On")
589 return true;
590 else
591 return false;
592}
593
63a65070
SL
594void wxWebViewIE::SelectAll()
595{
596 ExecCommand("SelectAll");
597}
598
e669ddde 599bool wxWebViewIE::HasSelection() const
63a65070
SL
600{
601 IHTMLDocument2* document = GetDocument();
602 IHTMLSelectionObject* selection;
423adfde 603 wxString sel;
7fbc727b
SL
604 HRESULT hr = document->get_selection(&selection);
605 if(SUCCEEDED(hr))
606 {
423adfde 607 BSTR type;
7fbc727b 608 selection->get_type(&type);
423adfde 609 sel = wxString(type);
7fbc727b
SL
610 selection->Release();
611 }
612 document->Release();
423adfde 613 return sel != "None";
63a65070
SL
614}
615
616void wxWebViewIE::DeleteSelection()
617{
618 ExecCommand("Delete");
619}
620
e669ddde 621wxString wxWebViewIE::GetSelectedText() const
c9355a3d
SL
622{
623 IHTMLDocument2* document = GetDocument();
624 IHTMLSelectionObject* selection;
625 wxString selected;
626 HRESULT hr = document->get_selection(&selection);
627 if(SUCCEEDED(hr))
628 {
629 IDispatch* disrange;
630 hr = selection->createRange(&disrange);
631 if(SUCCEEDED(hr))
632 {
633 IHTMLTxtRange* range;
634 hr = disrange->QueryInterface(IID_IHTMLTxtRange, (void**)&range);
635 if(SUCCEEDED(hr))
636 {
637 BSTR text;
638 range->get_text(&text);
639 selected = wxString(text);
640 range->Release();
641 }
642 disrange->Release();
643 }
644 selection->Release();
645 }
646 document->Release();
647 return selected;
648}
649
e669ddde 650wxString wxWebViewIE::GetSelectedSource() const
0fe8a1b6
SL
651{
652 IHTMLDocument2* document = GetDocument();
653 IHTMLSelectionObject* selection;
654 wxString selected;
655 HRESULT hr = document->get_selection(&selection);
656 if(SUCCEEDED(hr))
657 {
658 IDispatch* disrange;
659 hr = selection->createRange(&disrange);
660 if(SUCCEEDED(hr))
661 {
662 IHTMLTxtRange* range;
663 hr = disrange->QueryInterface(IID_IHTMLTxtRange, (void**)&range);
664 if(SUCCEEDED(hr))
665 {
666 BSTR text;
667 range->get_htmlText(&text);
668 selected = wxString(text);
669 range->Release();
670 }
671 disrange->Release();
672 }
673 selection->Release();
674 }
675 document->Release();
676 return selected;
677}
678
41933aa5
SL
679void wxWebViewIE::ClearSelection()
680{
681 IHTMLDocument2* document = GetDocument();
682 IHTMLSelectionObject* selection;
683 wxString selected;
684 HRESULT hr = document->get_selection(&selection);
685 if(SUCCEEDED(hr))
686 {
687 selection->empty();
688 selection->Release();
689 }
690 document->Release();
691}
692
e669ddde 693wxString wxWebViewIE::GetPageText() const
241b769f
SL
694{
695 IHTMLDocument2* document = GetDocument();
423adfde 696 wxString text;
241b769f
SL
697 IHTMLElement* body;
698 HRESULT hr = document->get_body(&body);
699 if(SUCCEEDED(hr))
700 {
423adfde 701 BSTR out;
241b769f 702 body->get_innerText(&out);
423adfde 703 text = wxString(out);
241b769f
SL
704 body->Release();
705 }
706 document->Release();
423adfde 707 return text;
241b769f
SL
708}
709
c9ccc09c
SL
710void wxWebViewIE::RunScript(const wxString& javascript)
711{
712 IHTMLDocument2* document = GetDocument();
713 IHTMLWindow2* window;
714 wxString language = "javascript";
715 HRESULT hr = document->get_parentWindow(&window);
716 if(SUCCEEDED(hr))
717 {
718 VARIANT level;
719 VariantInit(&level);
720 V_VT(&level) = VT_EMPTY;
c9a828e7 721 window->execScript(SysAllocString(javascript.wc_str()),
ee8bc1a8 722 SysAllocString(language.wc_str()),
c9a828e7 723 &level);
c9ccc09c
SL
724 }
725 document->Release();
726}
727
7d8d6163 728void wxWebViewIE::RegisterHandler(wxSharedPtr<wxWebViewHandler> handler)
29365629 729{
e924e848
SL
730 wxDynamicLibrary urlMon(wxT("urlmon.dll"));
731 if(urlMon.HasSymbol(wxT("CoInternetGetSession")))
29365629 732 {
f559d1a2 733 typedef HRESULT (WINAPI *CoInternetGetSession_t)(DWORD, wxIInternetSession**, DWORD);
e924e848
SL
734 wxDYNLIB_FUNCTION(CoInternetGetSession_t, CoInternetGetSession, urlMon);
735
736 ClassFactory* cf = new ClassFactory(handler);
f559d1a2 737 wxIInternetSession* session;
e924e848
SL
738 HRESULT res = (*pfnCoInternetGetSession)(0, &session, 0);
739 if(FAILED(res))
740 {
741 wxFAIL_MSG("Could not retrive internet session");
742 }
29365629 743
c9a828e7
VZ
744 HRESULT hr = session->RegisterNameSpace(cf, CLSID_FileProtocol,
745 handler->GetName().wc_str(),
746 0, NULL, 0);
e924e848
SL
747 if(FAILED(hr))
748 {
749 wxFAIL_MSG("Could not register protocol");
750 }
39498710 751 m_factories.push_back(cf);
e924e848
SL
752 }
753 else
29365629 754 {
e924e848 755 wxFAIL_MSG("urlmon does not contain CoInternetGetSession");
29365629
SL
756 }
757}
758
e669ddde 759bool wxWebViewIE::CanExecCommand(wxString command) const
4681a3ea 760{
617227c3 761 IHTMLDocument2* document = GetDocument();
4681a3ea 762 VARIANT_BOOL enabled;
7fbc727b 763
4681a3ea 764 document->queryCommandEnabled(SysAllocString(command.wc_str()), &enabled);
7fbc727b 765 document->Release();
4681a3ea
SL
766
767 return (enabled == VARIANT_TRUE);
768}
769
770void wxWebViewIE::ExecCommand(wxString command)
771{
617227c3
SL
772 IHTMLDocument2* document = GetDocument();
773 document->execCommand(SysAllocString(command.wc_str()), VARIANT_FALSE, VARIANT(), NULL);
7fbc727b 774 document->Release();
617227c3 775}
4681a3ea 776
e669ddde 777IHTMLDocument2* wxWebViewIE::GetDocument() const
617227c3
SL
778{
779 wxVariant variant = m_ie.GetProperty("Document");
780 IHTMLDocument2* document = (IHTMLDocument2*)variant.GetVoidPtr();
4681a3ea 781
617227c3
SL
782 wxASSERT(document);
783
784 return document;
4681a3ea
SL
785}
786
61b98a2d
SL
787void wxWebViewIE::onActiveXEvent(wxActiveXEvent& evt)
788{
789 if (m_webBrowser == NULL) return;
790
791 switch (evt.GetDispatchId())
792 {
793 case DISPID_BEFORENAVIGATE2:
794 {
795 m_isBusy = true;
796
797 wxString url = evt[1].GetString();
798 wxString target = evt[3].GetString();
799
04fa04d8 800 wxWebViewEvent event(wxEVT_COMMAND_WEB_VIEW_NAVIGATING,
3225a4b8 801 GetId(), url, target);
e11b9a6b
SL
802
803 //skip empty javascript events.
804 if(url == "javascript:\"\"" && target.IsEmpty())
805 {
806 event.Veto();
807 }
808 else
809 {
810 event.SetEventObject(this);
811 HandleWindowEvent(event);
812 }
61b98a2d 813
3225a4b8 814 if (!event.IsAllowed())
61b98a2d
SL
815 {
816 wxActiveXEventNativeMSW* nativeParams =
817 evt.GetNativeParameters();
818 *V_BOOLREF(&nativeParams->pDispParams->rgvarg[0]) = VARIANT_TRUE;
819 }
820
821 // at this point, either the navigation event has been cancelled
822 // and we're not busy, either it was accepted and IWebBrowser2's
823 // Busy property will be true; so we don't need our override
824 // flag anymore.
825 m_isBusy = false;
826
827 break;
828 }
829
830 case DISPID_NAVIGATECOMPLETE2:
831 {
832 wxString url = evt[1].GetString();
833 // TODO: set target parameter if possible
834 wxString target = wxEmptyString;
04fa04d8 835 wxWebViewEvent event(wxEVT_COMMAND_WEB_VIEW_NAVIGATED,
3225a4b8 836 GetId(), url, target);
61b98a2d
SL
837 event.SetEventObject(this);
838 HandleWindowEvent(event);
839 break;
840 }
841
842 case DISPID_PROGRESSCHANGE:
843 {
844 // download progress
845 break;
846 }
847
848 case DISPID_DOCUMENTCOMPLETE:
849 {
3ee442ff
SL
850 //Only send a complete even if we are actually finished, this brings
851 //the event in to line with webkit
852 READYSTATE rs;
853 m_webBrowser->get_ReadyState( &rs );
854 if(rs != READYSTATE_COMPLETE)
855 break;
856
61b98a2d 857 wxString url = evt[1].GetString();
113e0a92
SL
858
859 //As we are complete we also add to the history list, but not if the
860 //page is not the main page, ie it is a subframe
60eabdbe 861 //We also have to check if we are loading a file:// url, if so we
f239a200
SL
862 //need to change the comparison as ie passes back a different style
863 //of url
60eabdbe
VZ
864 if(m_historyEnabled && !m_historyLoadingFromList &&
865 (url == GetCurrentURL() ||
866 (GetCurrentURL().substr(0, 4) == "file" &&
f239a200 867 wxFileSystem::URLToFileName(GetCurrentURL()).GetFullPath() == url)))
74af0b13
SL
868 {
869 //If we are not at the end of the list, then erase everything
870 //between us and the end before adding the new page
22ca10fa 871 if(m_historyPosition != static_cast<int>(m_historyList.size()) - 1)
74af0b13
SL
872 {
873 m_historyList.erase(m_historyList.begin() + m_historyPosition + 1,
874 m_historyList.end());
875 }
c13d6ac1 876 wxSharedPtr<wxWebViewHistoryItem> item(new wxWebViewHistoryItem(url, GetCurrentTitle()));
74af0b13
SL
877 m_historyList.push_back(item);
878 m_historyPosition++;
879 }
880 //Reset as we are done now
881 m_historyLoadingFromList = false;
61b98a2d
SL
882 // TODO: set target parameter if possible
883 wxString target = wxEmptyString;
04fa04d8 884 wxWebViewEvent event(wxEVT_COMMAND_WEB_VIEW_LOADED, GetId(),
3225a4b8 885 url, target);
61b98a2d
SL
886 event.SetEventObject(this);
887 HandleWindowEvent(event);
888 break;
889 }
890
891 case DISPID_STATUSTEXTCHANGE:
892 {
893 break;
894 }
895
896 case DISPID_TITLECHANGE:
897 {
153530af
SL
898 wxString title = evt[0].GetString();
899
04fa04d8 900 wxWebViewEvent event(wxEVT_COMMAND_WEB_VIEW_TITLE_CHANGED,
3225a4b8 901 GetId(), GetCurrentURL(), "");
153530af
SL
902 event.SetString(title);
903 event.SetEventObject(this);
904 HandleWindowEvent(event);
61b98a2d
SL
905 break;
906 }
907
908 case DISPID_NAVIGATEERROR:
909 {
04fa04d8 910 wxWebViewNavigationError errorType = wxWEB_NAV_ERR_OTHER;
61b98a2d
SL
911 wxString errorCode = "?";
912 switch (evt[3].GetLong())
913 {
914 case INET_E_INVALID_URL: // (0x800C0002L or -2146697214)
915 errorCode = "INET_E_INVALID_URL";
916 errorType = wxWEB_NAV_ERR_REQUEST;
917 break;
918 case INET_E_NO_SESSION: // (0x800C0003L or -2146697213)
919 errorCode = "INET_E_NO_SESSION";
920 errorType = wxWEB_NAV_ERR_CONNECTION;
921 break;
922 case INET_E_CANNOT_CONNECT: // (0x800C0004L or -2146697212)
923 errorCode = "INET_E_CANNOT_CONNECT";
924 errorType = wxWEB_NAV_ERR_CONNECTION;
925 break;
926 case INET_E_RESOURCE_NOT_FOUND: // (0x800C0005L or -2146697211)
927 errorCode = "INET_E_RESOURCE_NOT_FOUND";
928 errorType = wxWEB_NAV_ERR_NOT_FOUND;
929 break;
930 case INET_E_OBJECT_NOT_FOUND: // (0x800C0006L or -2146697210)
931 errorCode = "INET_E_OBJECT_NOT_FOUND";
932 errorType = wxWEB_NAV_ERR_NOT_FOUND;
933 break;
934 case INET_E_DATA_NOT_AVAILABLE: // (0x800C0007L or -2146697209)
935 errorCode = "INET_E_DATA_NOT_AVAILABLE";
936 errorType = wxWEB_NAV_ERR_NOT_FOUND;
937 break;
938 case INET_E_DOWNLOAD_FAILURE: // (0x800C0008L or -2146697208)
939 errorCode = "INET_E_DOWNLOAD_FAILURE";
940 errorType = wxWEB_NAV_ERR_CONNECTION;
941 break;
942 case INET_E_AUTHENTICATION_REQUIRED: // (0x800C0009L or -2146697207)
943 errorCode = "INET_E_AUTHENTICATION_REQUIRED";
944 errorType = wxWEB_NAV_ERR_AUTH;
945 break;
946 case INET_E_NO_VALID_MEDIA: // (0x800C000AL or -2146697206)
947 errorCode = "INET_E_NO_VALID_MEDIA";
948 errorType = wxWEB_NAV_ERR_REQUEST;
949 break;
950 case INET_E_CONNECTION_TIMEOUT: // (0x800C000BL or -2146697205)
951 errorCode = "INET_E_CONNECTION_TIMEOUT";
952 errorType = wxWEB_NAV_ERR_CONNECTION;
953 break;
954 case INET_E_INVALID_REQUEST: // (0x800C000CL or -2146697204)
955 errorCode = "INET_E_INVALID_REQUEST";
956 errorType = wxWEB_NAV_ERR_REQUEST;
957 break;
958 case INET_E_UNKNOWN_PROTOCOL: // (0x800C000DL or -2146697203)
959 errorCode = "INET_E_UNKNOWN_PROTOCOL";
960 errorType = wxWEB_NAV_ERR_REQUEST;
961 break;
962 case INET_E_SECURITY_PROBLEM: // (0x800C000EL or -2146697202)
963 errorCode = "INET_E_SECURITY_PROBLEM";
964 errorType = wxWEB_NAV_ERR_SECURITY;
965 break;
966 case INET_E_CANNOT_LOAD_DATA: // (0x800C000FL or -2146697201)
967 errorCode = "INET_E_CANNOT_LOAD_DATA";
968 errorType = wxWEB_NAV_ERR_OTHER;
969 break;
970 case INET_E_CANNOT_INSTANTIATE_OBJECT:
971 // CoCreateInstance will return an error code if this happens,
972 // we'll handle this above.
973 return;
974 break;
975 case INET_E_REDIRECT_FAILED: // (0x800C0014L or -2146697196)
976 errorCode = "INET_E_REDIRECT_FAILED";
977 errorType = wxWEB_NAV_ERR_OTHER;
978 break;
979 case INET_E_REDIRECT_TO_DIR: // (0x800C0015L or -2146697195)
980 errorCode = "INET_E_REDIRECT_TO_DIR";
981 errorType = wxWEB_NAV_ERR_REQUEST;
982 break;
983 case INET_E_CANNOT_LOCK_REQUEST: // (0x800C0016L or -2146697194)
984 errorCode = "INET_E_CANNOT_LOCK_REQUEST";
985 errorType = wxWEB_NAV_ERR_OTHER;
986 break;
987 case INET_E_USE_EXTEND_BINDING: // (0x800C0017L or -2146697193)
988 errorCode = "INET_E_USE_EXTEND_BINDING";
989 errorType = wxWEB_NAV_ERR_OTHER;
990 break;
991 case INET_E_TERMINATED_BIND: // (0x800C0018L or -2146697192)
992 errorCode = "INET_E_TERMINATED_BIND";
993 errorType = wxWEB_NAV_ERR_OTHER;
994 break;
995 case INET_E_INVALID_CERTIFICATE: // (0x800C0019L or -2146697191)
996 errorCode = "INET_E_INVALID_CERTIFICATE";
997 errorType = wxWEB_NAV_ERR_CERTIFICATE;
998 break;
999 case INET_E_CODE_DOWNLOAD_DECLINED: // (0x800C0100L or -2146696960)
1000 errorCode = "INET_E_CODE_DOWNLOAD_DECLINED";
1001 errorType = wxWEB_NAV_ERR_USER_CANCELLED;
1002 break;
1003 case INET_E_RESULT_DISPATCHED: // (0x800C0200L or -2146696704)
1004 // cancel request cancelled...
1005 errorCode = "INET_E_RESULT_DISPATCHED";
1006 errorType = wxWEB_NAV_ERR_OTHER;
1007 break;
1008 case INET_E_CANNOT_REPLACE_SFP_FILE: // (0x800C0300L or -2146696448)
1009 errorCode = "INET_E_CANNOT_REPLACE_SFP_FILE";
1010 errorType = wxWEB_NAV_ERR_SECURITY;
1011 break;
1012 case INET_E_CODE_INSTALL_BLOCKED_BY_HASH_POLICY:
1013 errorCode = "INET_E_CODE_INSTALL_BLOCKED_BY_HASH_POLICY";
1014 errorType = wxWEB_NAV_ERR_SECURITY;
1015 break;
1016 case INET_E_CODE_INSTALL_SUPPRESSED:
1017 errorCode = "INET_E_CODE_INSTALL_SUPPRESSED";
1018 errorType = wxWEB_NAV_ERR_SECURITY;
1019 break;
1020 }
1021
1022 wxString url = evt[1].GetString();
1023 wxString target = evt[2].GetString();
04fa04d8 1024 wxWebViewEvent event(wxEVT_COMMAND_WEB_VIEW_ERROR, GetId(),
3225a4b8 1025 url, target);
61b98a2d
SL
1026 event.SetEventObject(this);
1027 event.SetInt(errorType);
1028 event.SetString(errorCode);
1029 HandleWindowEvent(event);
1030 break;
1031 }
853b6cd0 1032 case DISPID_NEWWINDOW3:
61b98a2d 1033 {
853b6cd0
SL
1034 wxString url = evt[4].GetString();
1035
04fa04d8 1036 wxWebViewEvent event(wxEVT_COMMAND_WEB_VIEW_NEWWINDOW,
3225a4b8 1037 GetId(), url, wxEmptyString);
853b6cd0
SL
1038 event.SetEventObject(this);
1039 HandleWindowEvent(event);
1040
d676fb21
SL
1041 //We always cancel this event otherwise an Internet Exporer window
1042 //is opened for the url
1043 wxActiveXEventNativeMSW* nativeParams = evt.GetNativeParameters();
1044 *V_BOOLREF(&nativeParams->pDispParams->rgvarg[3]) = VARIANT_TRUE;
be19c556
SL
1045 break;
1046 }
61b98a2d
SL
1047 }
1048
1049 evt.Skip();
1050}
1051
7d8d6163 1052VirtualProtocol::VirtualProtocol(wxSharedPtr<wxWebViewHandler> handler)
7d3f6b4d 1053{
7d3f6b4d 1054 m_file = NULL;
29365629 1055 m_handler = handler;
7d3f6b4d
SL
1056}
1057
9f194b9d
SL
1058BEGIN_IID_TABLE(VirtualProtocol)
1059 ADD_IID(Unknown)
1060 ADD_RAW_IID(wxIID_IInternetProtocolRoot)
1061 ADD_RAW_IID(wxIID_IInternetProtocol)
1062END_IID_TABLE;
7d3f6b4d 1063
9f194b9d 1064IMPLEMENT_IUNKNOWN_METHODS(VirtualProtocol)
7d3f6b4d 1065
f559d1a2
VZ
1066HRESULT VirtualProtocol::Start(LPCWSTR szUrl, wxIInternetProtocolSink *pOIProtSink,
1067 wxIInternetBindInfo *pOIBindInfo, DWORD grfPI,
0995b9dc 1068 HANDLE_PTR dwReserved)
7d3f6b4d 1069{
0995b9dc
SL
1070 wxUnusedVar(szUrl);
1071 wxUnusedVar(pOIBindInfo);
1072 wxUnusedVar(grfPI);
1073 wxUnusedVar(dwReserved);
7d3f6b4d 1074 m_protocolSink = pOIProtSink;
60eabdbe 1075
29365629
SL
1076 //We get the file itself from the protocol handler
1077 m_file = m_handler->GetFile(szUrl);
1078
7d3f6b4d
SL
1079
1080 if(!m_file)
1081 return INET_E_RESOURCE_NOT_FOUND;
1082
1083 //We return the stream length for current and total size as we can always
1084 //read the whole file from the stream
666f73c4 1085 wxFileOffset length = m_file->GetStream()->GetLength();
f559d1a2
VZ
1086 m_protocolSink->ReportData(wxBSCF_FIRSTDATANOTIFICATION |
1087 wxBSCF_DATAFULLYAVAILABLE |
1088 wxBSCF_LASTDATANOTIFICATION,
666f73c4 1089 length, length);
60eabdbe 1090 return S_OK;
7d3f6b4d
SL
1091}
1092
1093HRESULT VirtualProtocol::Read(void *pv, ULONG cb, ULONG *pcbRead)
1094{
1095 //If the file is null we return false to indicte it is finished
60eabdbe 1096 if(!m_file)
7d3f6b4d
SL
1097 return S_FALSE;
1098
1099 wxStreamError err = m_file->GetStream()->Read(pv, cb).GetLastError();
1100 *pcbRead = m_file->GetStream()->LastRead();
1101
1102 if(err == wxSTREAM_NO_ERROR)
1103 {
1104 if(*pcbRead < cb)
1105 {
1106 wxDELETE(m_file);
1107 m_protocolSink->ReportResult(S_OK, 0, NULL);
1108 }
1109 //As we are not eof there is more data
1110 return S_OK;
1111 }
1112 else if(err == wxSTREAM_EOF)
1113 {
1114 wxDELETE(m_file);
1115 m_protocolSink->ReportResult(S_OK, 0, NULL);
1116 //We are eof and so finished
1117 return S_OK;
1118 }
1119 else if(err == wxSTREAM_READ_ERROR)
1120 {
1121 wxDELETE(m_file);
1122 return INET_E_DOWNLOAD_FAILURE;
1123 }
0995b9dc
SL
1124 else
1125 {
1126 //Dummy return to surpress a compiler warning
1127 wxFAIL;
1128 return INET_E_DOWNLOAD_FAILURE;
1129 }
7d3f6b4d
SL
1130}
1131
9f194b9d
SL
1132BEGIN_IID_TABLE(ClassFactory)
1133 ADD_IID(Unknown)
1134 ADD_IID(ClassFactory)
1135END_IID_TABLE;
1136
1137IMPLEMENT_IUNKNOWN_METHODS(ClassFactory)
1138
7d3f6b4d
SL
1139HRESULT ClassFactory::CreateInstance(IUnknown* pUnkOuter, REFIID riid,
1140 void ** ppvObject)
1141{
60eabdbe 1142 if (pUnkOuter)
7d3f6b4d 1143 return CLASS_E_NOAGGREGATION;
29365629 1144 VirtualProtocol* vp = new VirtualProtocol(m_handler);
7d3f6b4d
SL
1145 vp->AddRef();
1146 HRESULT hr = vp->QueryInterface(riid, ppvObject);
1147 vp->Release();
1148 return hr;
1149
60eabdbe 1150}
7d3f6b4d
SL
1151
1152STDMETHODIMP ClassFactory::LockServer(BOOL fLock)
1153{
0995b9dc
SL
1154 wxUnusedVar(fLock);
1155 return S_OK;
7d3f6b4d
SL
1156}
1157
9d2f31db 1158#endif // wxUSE_WEBVIEW && wxUSE_WEBVIEW_IE