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