1 #include "IEHtmlWin.h"
2 #include <wx/strconv.h>
3 #include <wx/string.h>
4 #include <wx/event.h>
5 #include <wx/listctrl.h>
6 #include <wx/mstream.h>
7 #include <oleidl.h>
8 #include <winerror.h>
9 #include <exdispid.h>
10 #include <exdisp.h>
11 #include <olectl.h>
12 #include <Mshtml.h>
13 #include <sstream>
14 using namespace std;
15 
16 DEFINE_EVENT_TYPE(wxEVT_COMMAND_MSHTML_BEFORENAVIGATE2);
17 DEFINE_EVENT_TYPE(wxEVT_COMMAND_MSHTML_NEWWINDOW2);
18 DEFINE_EVENT_TYPE(wxEVT_COMMAND_MSHTML_DOCUMENTCOMPLETE);
19 DEFINE_EVENT_TYPE(wxEVT_COMMAND_MSHTML_PROGRESSCHANGE);
20 DEFINE_EVENT_TYPE(wxEVT_COMMAND_MSHTML_STATUSTEXTCHANGE);
21 DEFINE_EVENT_TYPE(wxEVT_COMMAND_MSHTML_TITLECHANGE);
22 
23 IMPLEMENT_DYNAMIC_CLASS(wxMSHTMLEvent, wxNotifyEvent);
24 
25 
26 //////////////////////////////////////////////////////////////////////
27 BEGIN_EVENT_TABLE(wxIEHtmlWin, wxActiveX)
28 END_EVENT_TABLE()
29 
30 class FS_DWebBrowserEvents2 : public IDispatch
31 {
32 private:
33     DECLARE_OLE_UNKNOWN(FS_DWebBrowserEvents2);
34 
35 
36     wxIEHtmlWin *m_iewin;
37 
38 public:
FS_DWebBrowserEvents2(wxIEHtmlWin * iewin)39     FS_DWebBrowserEvents2(wxIEHtmlWin *iewin) : m_iewin(iewin) {}
~FS_DWebBrowserEvents2()40 	virtual ~FS_DWebBrowserEvents2()
41     {
42     }
43 
44 	//IDispatch
GetIDsOfNames(REFIID r,OLECHAR ** o,unsigned int i,LCID l,DISPID * d)45 	STDMETHODIMP GetIDsOfNames(REFIID r, OLECHAR** o, unsigned int i, LCID l, DISPID* d)
46 	{
47         return E_NOTIMPL;
48     };
49 
GetTypeInfo(unsigned int i,LCID l,ITypeInfo ** t)50 	STDMETHODIMP GetTypeInfo(unsigned int i, LCID l, ITypeInfo** t)
51 	{
52         return E_NOTIMPL;
53     };
54 
GetTypeInfoCount(unsigned int * i)55 	STDMETHODIMP GetTypeInfoCount(unsigned int* i)
56 	{
57         return E_NOTIMPL;
58     };
59 
Post(WXTYPE etype,wxString text,long l1=0,long l2=0)60 	void Post(WXTYPE etype, wxString text, long l1 = 0, long l2 = 0)
61 	{
62 		if (! m_iewin || ! m_iewin->GetParent())
63 			return;
64 
65 		wxMSHTMLEvent event;
66 		event.SetId(m_iewin->GetId());
67 		event.SetEventType(etype);
68 		event.m_text1 = text;
69 		event.m_long1 = l1;
70 		event.m_long2 = l2;
71 
72 		m_iewin->GetParent()->AddPendingEvent(event);
73 	};
74 
Process(WXTYPE etype,wxString text=_T (""),long l1=0,long l2=0)75 	bool Process(WXTYPE etype, wxString text = _T(""), long l1 = 0, long l2 = 0)
76 	{
77 		if (! m_iewin || ! m_iewin->GetParent())
78 			return true;
79 
80 		wxMSHTMLEvent event;
81 		event.SetId(m_iewin->GetId());
82 		event.SetEventType(etype);
83 		event.m_text1 = text;
84 		event.m_long1 = l1;
85 		event.m_long2 = l2;
86 
87 		m_iewin->GetParent()->ProcessEvent(event);
88 
89 		return event.IsAllowed();
90 	};
91 
GetStrArg(VARIANT & v)92 	wxString GetStrArg(VARIANT& v)
93 	{
94 		VARTYPE vt = v.vt & ~VT_BYREF;
95 
96 		if (vt == VT_VARIANT)
97 			return GetStrArg(*v.pvarVal);
98 		else if (vt == VT_BSTR)
99 		{
100 			if (v.vt & VT_BYREF)
101 				return (v.pbstrVal ? *v.pbstrVal : L"");
102 			else
103 				return v.bstrVal;
104 		}
105 		else
106 			return _T("");
107 	};
108 
109 #define STR_ARG(arg) GetStrArg(pDispParams->rgvarg[arg])
110 
111 #define LONG_ARG(arg)\
112 			(pDispParams->rgvarg[arg].lVal)
113 
114 
Invoke(DISPID dispIdMember,REFIID riid,LCID lcid,WORD wFlags,DISPPARAMS * pDispParams,VARIANT * pVarResult,EXCEPINFO * pExcepInfo,unsigned int * puArgErr)115 	STDMETHODIMP Invoke(DISPID dispIdMember, REFIID riid, LCID lcid,
116 						  WORD wFlags, DISPPARAMS * pDispParams,
117 						  VARIANT * pVarResult, EXCEPINFO * pExcepInfo,
118 						  unsigned int * puArgErr)
119 	{
120 	    if (wFlags & DISPATCH_PROPERTYGET)
121             return E_NOTIMPL;
122 
123 	    switch (dispIdMember)
124 	    {
125 		    case DISPID_BEFORENAVIGATE2:
126 				if (Process(wxEVT_COMMAND_MSHTML_BEFORENAVIGATE2, STR_ARG(5)))
127 					*pDispParams->rgvarg->pboolVal = VARIANT_FALSE;
128 				else
129 					*pDispParams->rgvarg->pboolVal = VARIANT_TRUE;
130 				break;
131 
132 		    case DISPID_NEWWINDOW2:
133 				if (Process(wxEVT_COMMAND_MSHTML_NEWWINDOW2))
134 					*pDispParams->rgvarg->pboolVal = VARIANT_FALSE;
135 				else
136 					*pDispParams->rgvarg->pboolVal = VARIANT_TRUE;
137 				break;
138 
139             case DISPID_PROGRESSCHANGE:
140 				Post(wxEVT_COMMAND_MSHTML_PROGRESSCHANGE, _T(""), LONG_ARG(1), LONG_ARG(0));
141 				break;
142 
143             case DISPID_DOCUMENTCOMPLETE:
144 				Post(wxEVT_COMMAND_MSHTML_DOCUMENTCOMPLETE, STR_ARG(0));
145 				break;
146 
147             case DISPID_STATUSTEXTCHANGE:
148 				Post(wxEVT_COMMAND_MSHTML_STATUSTEXTCHANGE, STR_ARG(0));
149 				break;
150 
151             case DISPID_TITLECHANGE:
152 				Post(wxEVT_COMMAND_MSHTML_TITLECHANGE, STR_ARG(0));
153 				break;
154 	    }
155 
156     	return S_OK;
157     }
158 };
159 
160 #undef STR_ARG
161 
162 DEFINE_OLE_TABLE(FS_DWebBrowserEvents2)
163 	OLE_IINTERFACE(IUnknown)
164 	OLE_INTERFACE(DIID_DWebBrowserEvents2, DWebBrowserEvents2)
165 END_OLE_TABLE;
166 
167 
168 static const CLSID CLSID_MozillaBrowser =
169 { 0x1339B54C, 0x3453, 0x11D2,
170   { 0x93, 0xB9, 0x00, 0x00,
171     0x00, 0x00, 0x00, 0x00 } };
172 
173 
174 //#define PROGID "Shell.Explorer"
175 #define PROGID CLSID_WebBrowser
176 //#define PROGID CLSID_MozillaBrowser
177 //#define PROGID CLSID_HTMLDocument
178 //#define PROGID "MSCAL.Calendar"
179 //#define PROGID "WordPad.Document.1"
180 //#define PROGID "SoftwareFX.ChartFX.20"
181 
wxIEHtmlWin(wxWindow * parent,wxWindowID id,const wxPoint & pos,const wxSize & size,long style,const wxString & name)182 wxIEHtmlWin::wxIEHtmlWin(wxWindow * parent, wxWindowID id,
183         const wxPoint& pos,
184         const wxSize& size,
185         long style,
186         const wxString& name) :
187     wxActiveX(parent, PROGID, id, pos, size, style, name)
188 {
189     SetupBrowser();
190 }
191 
192 
~wxIEHtmlWin()193 wxIEHtmlWin::~wxIEHtmlWin()
194 {
195 }
196 
SetupBrowser()197 void wxIEHtmlWin::SetupBrowser()
198 {
199 	HRESULT hret;
200 
201 	// Get IWebBrowser2 Interface
202 	hret = m_webBrowser.QueryInterface(IID_IWebBrowser2, m_ActiveX);
203 	assert(SUCCEEDED(hret));
204 
205 	// Web Browser Events
206 	FS_DWebBrowserEvents2 *events = new FS_DWebBrowserEvents2(this);
207 	hret = ConnectAdvise(DIID_DWebBrowserEvents2, events);
208 	if (! SUCCEEDED(hret))
209 		delete events;
210 
211 	// web browser setup
212 	m_webBrowser->put_MenuBar(VARIANT_FALSE);
213 	m_webBrowser->put_AddressBar(VARIANT_FALSE);
214 	m_webBrowser->put_StatusBar(VARIANT_FALSE);
215 	m_webBrowser->put_ToolBar(VARIANT_FALSE);
216 
217 	m_webBrowser->put_RegisterAsBrowser(VARIANT_TRUE);
218 	m_webBrowser->put_RegisterAsDropTarget(VARIANT_TRUE);
219 
220     m_webBrowser->Navigate( L"about:blank", NULL, NULL, NULL, NULL );
221 }
222 
223 
SetEditMode(bool seton)224 void wxIEHtmlWin::SetEditMode(bool seton)
225 {
226     m_bAmbientUserMode = ! seton;
227     AmbientPropertyChanged(DISPID_AMBIENT_USERMODE);
228 };
229 
GetEditMode()230 bool wxIEHtmlWin::GetEditMode()
231 {
232     return ! m_bAmbientUserMode;
233 };
234 
235 
SetCharset(wxString charset)236 void wxIEHtmlWin::SetCharset(wxString charset)
237 {
238 	// HTML Document ?
239 	IDispatch *pDisp = NULL;
240 	HRESULT hret = m_webBrowser->get_Document(&pDisp);
241 	wxAutoOleInterface<IDispatch> disp(pDisp);
242 
243 	if (disp.Ok())
244 	{
245 		wxAutoOleInterface<IHTMLDocument2> doc(IID_IHTMLDocument2, disp);
246 		if (doc.Ok())
247             doc->put_charset((BSTR) (const wchar_t *) charset.wc_str(wxConvUTF8));
248 			//doc->put_charset((BSTR) wxConvUTF8.cMB2WC(charset).data());
249 	};
250 };
251 
252 
253 class IStreamAdaptorBase : public IStream
254 {
255 private:
256     DECLARE_OLE_UNKNOWN(IStreamAdaptorBase);
257 
258 public:
IStreamAdaptorBase()259     IStreamAdaptorBase() {}
~IStreamAdaptorBase()260     virtual ~IStreamAdaptorBase() {}
261 
262     // ISequentialStream
263     HRESULT STDMETHODCALLTYPE Read(void __RPC_FAR *pv, ULONG cb, ULONG __RPC_FAR *pcbRead) = 0;
Write(const void __RPC_FAR * pv,ULONG cb,ULONG __RPC_FAR * pcbWritten)264     HRESULT STDMETHODCALLTYPE Write(const void __RPC_FAR *pv, ULONG cb, ULONG __RPC_FAR *pcbWritten) {return E_NOTIMPL;}
265 
266     // IStream
Seek(LARGE_INTEGER dlibMove,DWORD dwOrigin,ULARGE_INTEGER __RPC_FAR * plibNewPosition)267     HRESULT STDMETHODCALLTYPE Seek(LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER __RPC_FAR *plibNewPosition) {return E_NOTIMPL;}
SetSize(ULARGE_INTEGER libNewSize)268     HRESULT STDMETHODCALLTYPE SetSize(ULARGE_INTEGER libNewSize) {return E_NOTIMPL;}
CopyTo(IStream __RPC_FAR * pstm,ULARGE_INTEGER cb,ULARGE_INTEGER __RPC_FAR * pcbRead,ULARGE_INTEGER __RPC_FAR * pcbWritten)269     HRESULT STDMETHODCALLTYPE CopyTo(IStream __RPC_FAR *pstm, ULARGE_INTEGER cb, ULARGE_INTEGER __RPC_FAR *pcbRead, ULARGE_INTEGER __RPC_FAR *pcbWritten) {return E_NOTIMPL;}
Commit(DWORD grfCommitFlags)270     HRESULT STDMETHODCALLTYPE Commit(DWORD grfCommitFlags) {return E_NOTIMPL;}
Revert(void)271     HRESULT STDMETHODCALLTYPE Revert(void) {return E_NOTIMPL;}
LockRegion(ULARGE_INTEGER libOffset,ULARGE_INTEGER cb,DWORD dwLockType)272     HRESULT STDMETHODCALLTYPE LockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType) {return E_NOTIMPL;}
UnlockRegion(ULARGE_INTEGER libOffset,ULARGE_INTEGER cb,DWORD dwLockType)273     HRESULT STDMETHODCALLTYPE UnlockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType) {return E_NOTIMPL;}
Stat(STATSTG __RPC_FAR * pstatstg,DWORD grfStatFlag)274     HRESULT STDMETHODCALLTYPE Stat(STATSTG __RPC_FAR *pstatstg, DWORD grfStatFlag) {return E_NOTIMPL;}
Clone(IStream __RPC_FAR * __RPC_FAR * ppstm)275     HRESULT STDMETHODCALLTYPE Clone(IStream __RPC_FAR *__RPC_FAR *ppstm) {return E_NOTIMPL;}
276 };
277 
278 DEFINE_OLE_TABLE(IStreamAdaptorBase)
279 	OLE_IINTERFACE(IUnknown)
280 	OLE_IINTERFACE(ISequentialStream)
281 	OLE_IINTERFACE(IStream)
282 END_OLE_TABLE;
283 
284 class IStreamAdaptor : public IStreamAdaptorBase
285 {
286 private:
287     istream *m_is;
288 
289 public:
290 
IStreamAdaptor(istream * is)291     IStreamAdaptor(istream *is)	: IStreamAdaptorBase(), m_is(is)
292     {
293         wxASSERT(m_is != NULL);
294     }
~IStreamAdaptor()295     ~IStreamAdaptor()
296     {
297         delete m_is;
298     }
299 
300     // ISequentialStream
Read(void __RPC_FAR * pv,ULONG cb,ULONG __RPC_FAR * pcbRead)301     HRESULT STDMETHODCALLTYPE Read(void __RPC_FAR *pv, ULONG cb, ULONG __RPC_FAR *pcbRead)
302 	{
303 		m_is->read((char *) pv, cb);
304 		if (pcbRead)
305 			*pcbRead = m_is->gcount();
306 
307 		return S_OK;
308 	};
309 };
310 
311 class IwxStreamAdaptor : public IStreamAdaptorBase
312 {
313 private:
314     wxInputStream *m_is;
315 
316 public:
317 
IwxStreamAdaptor(wxInputStream * is)318     IwxStreamAdaptor(wxInputStream *is)	: IStreamAdaptorBase(), m_is(is)
319     {
320         wxASSERT(m_is != NULL);
321     }
~IwxStreamAdaptor()322     ~IwxStreamAdaptor()
323     {
324         delete m_is;
325     }
326 
327     // ISequentialStream
Read(void __RPC_FAR * pv,ULONG cb,ULONG __RPC_FAR * pcbRead)328     HRESULT STDMETHODCALLTYPE Read(void __RPC_FAR *pv, ULONG cb, ULONG __RPC_FAR *pcbRead)
329 	{
330 		m_is->Read((char *) pv, cb);
331 		if (pcbRead)
332 			*pcbRead = m_is->LastRead();
333 
334 		return S_OK;
335 	};
336 };
337 
338 
LoadUrl(const wxString & url)339 void wxIEHtmlWin::LoadUrl(const wxString& url)
340 {
341 	VARIANTARG navFlag, targetFrame, postData, headers;
342 	navFlag.vt = VT_EMPTY;
343 	navFlag.vt = VT_I2;
344 	navFlag.iVal = navNoReadFromCache;
345 	targetFrame.vt = VT_EMPTY;
346 	postData.vt = VT_EMPTY;
347 	headers.vt = VT_EMPTY;
348 
349 	HRESULT hret = 0;
350 
351 	IDispatch *pDisp = NULL;
352 
353 	hret = m_webBrowser->get_Document(&pDisp);
354 	wxAutoOleInterface<IDispatch> disp(pDisp);
355 
356 #if 0
357 	if (m_webBrowser.Ok()&&disp.Ok())
358 	{
359 		wxAutoOleInterface<IHTMLDocument2> doc(IID_IHTMLDocument2, disp);
360 		if (doc.Ok()){
361 			IHTMLLocation *p;
362 			if( doc->get_location(&p) == S_OK )
363 			{
364 				hret=p->replace((BSTR) (const wchar_t *) url.wc_str(/*wxConvUTF8*/wxConvLocal));
365 				if( hret == S_OK )
366 					return;
367 			}
368 		}
369 	}
370 #endif
371 	hret = m_webBrowser->Navigate((BSTR) (const wchar_t *) url.wc_str(/*wxConvUTF8*/wxConvLocal),
372 		&navFlag, &targetFrame, &postData, &headers);
373 };
374 
375 class wxOwnedMemInputStream : public wxMemoryInputStream
376 {
377 public:
378     char *m_data;
379 
wxOwnedMemInputStream(char * data,size_t len)380     wxOwnedMemInputStream(char *data, size_t len) :
381         wxMemoryInputStream(data, len), m_data(data)
382     {}
~wxOwnedMemInputStream()383     ~wxOwnedMemInputStream()
384     {
385         free(m_data);
386     }
387 };
388 
LoadString(wxString html)389 bool  wxIEHtmlWin::LoadString(wxString html)
390 {
391     char *data = NULL;
392     size_t len = html.length();
393 #ifdef UNICODE
394     len *= 2;
395 #endif
396     data = (char *) malloc(len);
397     memcpy(data, html.c_str(), len);
398 	return LoadStream(new wxOwnedMemInputStream(data, len));
399 };
400 
LoadStream(IStreamAdaptorBase * pstrm)401 bool wxIEHtmlWin::LoadStream(IStreamAdaptorBase *pstrm)
402 {
403 	wxAutoOleInterface<IStream>	strm(pstrm);
404 
405     // Document Interface
406     IDispatch *pDisp = NULL;
407     HRESULT hret = m_webBrowser->get_Document(&pDisp);
408 	if (! pDisp)
409 		return false;
410 	wxAutoOleInterface<IDispatch> disp(pDisp);
411 
412 
413 	// get IPersistStreamInit
414     wxAutoOleInterface<IPersistStreamInit>
415 		pPersistStreamInit(IID_IPersistStreamInit, disp);
416 
417     if (pPersistStreamInit.Ok())
418     {
419         HRESULT hr = pPersistStreamInit->InitNew();
420         if (SUCCEEDED(hr))
421             hr = pPersistStreamInit->Load(strm);
422 
423 		return SUCCEEDED(hr);
424     }
425 	else
426 	    return false;
427 };
428 
LoadStream(istream * is)429 bool  wxIEHtmlWin::LoadStream(istream *is)
430 {
431 	// wrap reference around stream
432     IStreamAdaptor *pstrm = new IStreamAdaptor(is);
433 	pstrm->AddRef();
434 
435     return LoadStream(pstrm);
436 };
437 
LoadStream(wxInputStream * is)438 bool wxIEHtmlWin::LoadStream(wxInputStream *is)
439 {
440 	// wrap reference around stream
441     IwxStreamAdaptor *pstrm = new IwxStreamAdaptor(is);
442 	pstrm->AddRef();
443 
444     return LoadStream(pstrm);
445 };
446 
447 
GoBack()448 bool wxIEHtmlWin::GoBack()
449 {
450     HRESULT hret = 0;
451     hret = m_webBrowser->GoBack();
452     return hret == S_OK;
453 }
454 
GoForward()455 bool wxIEHtmlWin::GoForward()
456 {
457     HRESULT hret = 0;
458     hret = m_webBrowser->GoForward();
459     return hret == S_OK;
460 }
461 
GoHome()462 bool wxIEHtmlWin::GoHome()
463 {
464     HRESULT hret = 0;
465     hret = m_webBrowser->GoHome();
466     return hret == S_OK;
467 }
468 
GoSearch()469 bool wxIEHtmlWin::GoSearch()
470 {
471     HRESULT hret = 0;
472     hret = m_webBrowser->GoSearch();
473     return hret == S_OK;
474 }
475 
Refresh(wxIEHtmlRefreshLevel level)476 bool wxIEHtmlWin::Refresh(wxIEHtmlRefreshLevel level)
477 {
478     VARIANTARG levelArg;
479     HRESULT hret = 0;
480 
481     levelArg.vt = VT_I2;
482     levelArg.iVal = level;
483     hret = m_webBrowser->Refresh2(&levelArg);
484     return hret == S_OK;
485 }
486 
Stop()487 bool wxIEHtmlWin::Stop()
488 {
489     HRESULT hret = 0;
490     hret = m_webBrowser->Stop();
491     return hret == S_OK;
492 }
493 
494 
495 ///////////////////////////////////////////////////////////////////////////////
496 
GetSelObject(IOleObject * oleObject)497 static wxAutoOleInterface<IHTMLSelectionObject> GetSelObject(IOleObject *oleObject)
498 {
499 	// Query for IWebBrowser interface
500     wxAutoOleInterface<IWebBrowser2> wb(IID_IWebBrowser2, oleObject);
501     if (! wb.Ok())
502     	return wxAutoOleInterface<IHTMLSelectionObject>();
503 
504 	IDispatch *iDisp = NULL;
505     HRESULT hr = wb->get_Document(&iDisp);
506     if (hr != S_OK)
507     	return wxAutoOleInterface<IHTMLSelectionObject>();
508 
509 	// Query for Document Interface
510     wxAutoOleInterface<IHTMLDocument2> hd(IID_IHTMLDocument2, iDisp);
511     iDisp->Release();
512 
513     if (! hd.Ok())
514     	return wxAutoOleInterface<IHTMLSelectionObject>();
515 
516     IHTMLSelectionObject *_so = NULL;
517     hr = hd->get_selection(&_so);
518 
519     // take ownership of selection object
520 	wxAutoOleInterface<IHTMLSelectionObject> so(_so);
521 
522     return so;
523 };
524 
GetSelRange(IOleObject * oleObject)525 static wxAutoOleInterface<IHTMLTxtRange> GetSelRange(IOleObject *oleObject)
526 {
527 	wxAutoOleInterface<IHTMLTxtRange> tr;
528 
529     wxAutoOleInterface<IHTMLSelectionObject> so(GetSelObject(oleObject));
530     if (! so)
531     	return tr;
532 
533 	IDispatch *iDisp = NULL;
534     HRESULT hr = so->createRange(&iDisp);
535     if (hr != S_OK)
536     	return tr;
537 
538 	// Query for IHTMLTxtRange interface
539 	tr.QueryInterface(IID_IHTMLTxtRange, iDisp);
540     iDisp->Release();
541     return tr;
542 };
543 
544 
GetStringSelection(bool asHTML)545 wxString wxIEHtmlWin::GetStringSelection(bool asHTML)
546 {
547 	wxAutoOleInterface<IHTMLTxtRange> tr(GetSelRange(m_oleObject));
548     if (! tr)
549     	return _T("");
550 
551     BSTR text = NULL;
552     HRESULT hr = E_FAIL;
553 
554 	if (asHTML)
555 		hr = tr->get_htmlText(&text);
556 	else
557 		hr = tr->get_text(&text);
558     if (hr != S_OK)
559     	return _T("");
560 
561     wxString s = text;
562     SysFreeString(text);
563 
564     return s;
565 };
566 
GetText(bool asHTML)567 wxString wxIEHtmlWin::GetText(bool asHTML)
568 {
569 	if (! m_webBrowser.Ok())
570 		return _T("");
571 
572 	// get document dispatch interface
573 	IDispatch *iDisp = NULL;
574     HRESULT hr = m_webBrowser->get_Document(&iDisp);
575     if (hr != S_OK)
576     	return _T("");
577 
578 	// Query for Document Interface
579     wxAutoOleInterface<IHTMLDocument2> hd(IID_IHTMLDocument2, iDisp);
580     iDisp->Release();
581 
582     if (! hd.Ok())
583 		return _T("");
584 
585 	// get body element
586 	IHTMLElement *_body = NULL;
587 	hd->get_body(&_body);
588 	if (! _body)
589 		return _T("");
590 	wxAutoOleInterface<IHTMLElement> body(_body);
591 
592 	// get inner text
593     BSTR text = NULL;
594     hr = E_FAIL;
595 
596 	if (asHTML)
597 		hr = body->get_innerHTML(&text);
598 	else
599 		hr = body->get_innerText(&text);
600     if (hr != S_OK)
601     	return _T("");
602 
603     wxString s = text;
604     SysFreeString(text);
605 
606     return s;
607 };
608