#include "IEHtmlWin.h" #include #include #include #include #include #include #include #include #include #include #include #include using namespace std; DEFINE_EVENT_TYPE(wxEVT_COMMAND_MSHTML_BEFORENAVIGATE2); DEFINE_EVENT_TYPE(wxEVT_COMMAND_MSHTML_NEWWINDOW2); DEFINE_EVENT_TYPE(wxEVT_COMMAND_MSHTML_DOCUMENTCOMPLETE); DEFINE_EVENT_TYPE(wxEVT_COMMAND_MSHTML_PROGRESSCHANGE); DEFINE_EVENT_TYPE(wxEVT_COMMAND_MSHTML_STATUSTEXTCHANGE); DEFINE_EVENT_TYPE(wxEVT_COMMAND_MSHTML_TITLECHANGE); IMPLEMENT_DYNAMIC_CLASS(wxMSHTMLEvent, wxNotifyEvent); ////////////////////////////////////////////////////////////////////// BEGIN_EVENT_TABLE(wxIEHtmlWin, wxActiveX) END_EVENT_TABLE() class FS_DWebBrowserEvents2 : public IDispatch { private: DECLARE_OLE_UNKNOWN(FS_DWebBrowserEvents2); wxIEHtmlWin *m_iewin; public: FS_DWebBrowserEvents2(wxIEHtmlWin *iewin) : m_iewin(iewin) {} virtual ~FS_DWebBrowserEvents2() { } //IDispatch STDMETHODIMP GetIDsOfNames(REFIID r, OLECHAR** o, unsigned int i, LCID l, DISPID* d) { return E_NOTIMPL; }; STDMETHODIMP GetTypeInfo(unsigned int i, LCID l, ITypeInfo** t) { return E_NOTIMPL; }; STDMETHODIMP GetTypeInfoCount(unsigned int* i) { return E_NOTIMPL; }; void Post(WXTYPE etype, wxString text, long l1 = 0, long l2 = 0) { if (! m_iewin || ! m_iewin->GetParent()) return; wxMSHTMLEvent event; event.SetId(m_iewin->GetId()); event.SetEventType(etype); event.m_text1 = text; event.m_long1 = l1; event.m_long2 = l2; m_iewin->GetParent()->AddPendingEvent(event); }; bool Process(WXTYPE etype, wxString text = wxEmptyString, long l1 = 0, long l2 = 0) { if (! m_iewin || ! m_iewin->GetParent()) return true; wxMSHTMLEvent event; event.SetId(m_iewin->GetId()); event.SetEventType(etype); event.m_text1 = text; event.m_long1 = l1; event.m_long2 = l2; m_iewin->GetParent()->ProcessEvent(event); return event.IsAllowed(); }; wxString GetStrArg(VARIANT& v) { VARTYPE vt = v.vt & ~VT_BYREF; if (vt == VT_VARIANT) return GetStrArg(*v.pvarVal); else if (vt == VT_BSTR) { if (v.vt & VT_BYREF) return (v.pbstrVal ? *v.pbstrVal : L""); else return v.bstrVal; } else return wxEmptyString; }; #define STR_ARG(arg) GetStrArg(pDispParams->rgvarg[arg]) #define LONG_ARG(arg)\ (pDispParams->rgvarg[arg].lVal) STDMETHODIMP Invoke(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS * pDispParams, VARIANT * pVarResult, EXCEPINFO * pExcepInfo, unsigned int * puArgErr) { if (wFlags & DISPATCH_PROPERTYGET) return E_NOTIMPL; switch (dispIdMember) { case DISPID_BEFORENAVIGATE2: if (Process(wxEVT_COMMAND_MSHTML_BEFORENAVIGATE2, STR_ARG(5))) *pDispParams->rgvarg->pboolVal = VARIANT_FALSE; else *pDispParams->rgvarg->pboolVal = VARIANT_TRUE; break; case DISPID_NEWWINDOW2: if (Process(wxEVT_COMMAND_MSHTML_NEWWINDOW2)) *pDispParams->rgvarg->pboolVal = VARIANT_FALSE; else *pDispParams->rgvarg->pboolVal = VARIANT_TRUE; break; case DISPID_PROGRESSCHANGE: Post(wxEVT_COMMAND_MSHTML_PROGRESSCHANGE, wxEmptyString, LONG_ARG(1), LONG_ARG(0)); break; case DISPID_DOCUMENTCOMPLETE: Post(wxEVT_COMMAND_MSHTML_DOCUMENTCOMPLETE, STR_ARG(0)); break; case DISPID_STATUSTEXTCHANGE: Post(wxEVT_COMMAND_MSHTML_STATUSTEXTCHANGE, STR_ARG(0)); break; case DISPID_TITLECHANGE: Post(wxEVT_COMMAND_MSHTML_TITLECHANGE, STR_ARG(0)); break; } return S_OK; } }; #undef STR_ARG DEFINE_OLE_TABLE(FS_DWebBrowserEvents2) OLE_IINTERFACE(IUnknown) OLE_INTERFACE(DIID_DWebBrowserEvents2, DWebBrowserEvents2) END_OLE_TABLE; static const CLSID CLSID_MozillaBrowser = { 0x1339B54C, 0x3453, 0x11D2, { 0x93, 0xB9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }; //#define PROGID "Shell.Explorer" #define PROGID CLSID_WebBrowser //#define PROGID CLSID_MozillaBrowser //#define PROGID CLSID_HTMLDocument //#define PROGID "MSCAL.Calendar" //#define PROGID "WordPad.Document.1" //#define PROGID "SoftwareFX.ChartFX.20" wxIEHtmlWin::wxIEHtmlWin(wxWindow * parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style, const wxString& name) : wxActiveX(parent, PROGID, id, pos, size, style, name) { SetupBrowser(); } wxIEHtmlWin::~wxIEHtmlWin() { } void wxIEHtmlWin::SetupBrowser() { HRESULT hret; // Get IWebBrowser2 Interface hret = m_webBrowser.QueryInterface(IID_IWebBrowser2, m_ActiveX); assert(SUCCEEDED(hret)); // Web Browser Events FS_DWebBrowserEvents2 *events = new FS_DWebBrowserEvents2(this); hret = ConnectAdvise(DIID_DWebBrowserEvents2, events); if (! SUCCEEDED(hret)) delete events; // web browser setup m_webBrowser->put_MenuBar(VARIANT_FALSE); m_webBrowser->put_AddressBar(VARIANT_FALSE); m_webBrowser->put_StatusBar(VARIANT_FALSE); m_webBrowser->put_ToolBar(VARIANT_FALSE); m_webBrowser->put_RegisterAsBrowser(VARIANT_TRUE); m_webBrowser->put_RegisterAsDropTarget(VARIANT_TRUE); m_webBrowser->Navigate( L"about:blank", NULL, NULL, NULL, NULL ); } void wxIEHtmlWin::SetEditMode(bool seton) { m_bAmbientUserMode = ! seton; AmbientPropertyChanged(DISPID_AMBIENT_USERMODE); }; bool wxIEHtmlWin::GetEditMode() { return ! m_bAmbientUserMode; }; void wxIEHtmlWin::SetCharset(wxString charset) { // HTML Document ? IDispatch *pDisp = NULL; HRESULT hret = m_webBrowser->get_Document(&pDisp); wxAutoOleInterface disp(pDisp); if (disp.Ok()) { wxAutoOleInterface doc(IID_IHTMLDocument2, disp); if (doc.Ok()) doc->put_charset((BSTR) (const wchar_t *) charset.wc_str(wxConvUTF8)); //doc->put_charset((BSTR) wxConvUTF8.cMB2WC(charset).data()); }; }; class IStreamAdaptorBase : public IStream { private: DECLARE_OLE_UNKNOWN(IStreamAdaptorBase); public: IStreamAdaptorBase() {} virtual ~IStreamAdaptorBase() {} // ISequentialStream HRESULT STDMETHODCALLTYPE Read(void __RPC_FAR *pv, ULONG cb, ULONG __RPC_FAR *pcbRead) = 0; HRESULT STDMETHODCALLTYPE Write(const void __RPC_FAR *pv, ULONG cb, ULONG __RPC_FAR *pcbWritten) {return E_NOTIMPL;} // IStream HRESULT STDMETHODCALLTYPE Seek(LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER __RPC_FAR *plibNewPosition) {return E_NOTIMPL;} HRESULT STDMETHODCALLTYPE SetSize(ULARGE_INTEGER libNewSize) {return E_NOTIMPL;} HRESULT STDMETHODCALLTYPE CopyTo(IStream __RPC_FAR *pstm, ULARGE_INTEGER cb, ULARGE_INTEGER __RPC_FAR *pcbRead, ULARGE_INTEGER __RPC_FAR *pcbWritten) {return E_NOTIMPL;} HRESULT STDMETHODCALLTYPE Commit(DWORD grfCommitFlags) {return E_NOTIMPL;} HRESULT STDMETHODCALLTYPE Revert(void) {return E_NOTIMPL;} HRESULT STDMETHODCALLTYPE LockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType) {return E_NOTIMPL;} HRESULT STDMETHODCALLTYPE UnlockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType) {return E_NOTIMPL;} HRESULT STDMETHODCALLTYPE Stat(STATSTG __RPC_FAR *pstatstg, DWORD grfStatFlag) {return E_NOTIMPL;} HRESULT STDMETHODCALLTYPE Clone(IStream __RPC_FAR *__RPC_FAR *ppstm) {return E_NOTIMPL;} }; DEFINE_OLE_TABLE(IStreamAdaptorBase) OLE_IINTERFACE(IUnknown) OLE_IINTERFACE(ISequentialStream) OLE_IINTERFACE(IStream) END_OLE_TABLE; class IStreamAdaptor : public IStreamAdaptorBase { private: istream *m_is; public: IStreamAdaptor(istream *is) : IStreamAdaptorBase(), m_is(is) { wxASSERT(m_is != NULL); } ~IStreamAdaptor() { delete m_is; } // ISequentialStream HRESULT STDMETHODCALLTYPE Read(void __RPC_FAR *pv, ULONG cb, ULONG __RPC_FAR *pcbRead) { m_is->read((char *) pv, cb); if (pcbRead) *pcbRead = m_is->gcount(); return S_OK; }; }; class IwxStreamAdaptor : public IStreamAdaptorBase { private: wxInputStream *m_is; public: IwxStreamAdaptor(wxInputStream *is) : IStreamAdaptorBase(), m_is(is) { wxASSERT(m_is != NULL); } ~IwxStreamAdaptor() { delete m_is; } // ISequentialStream HRESULT STDMETHODCALLTYPE Read(void __RPC_FAR *pv, ULONG cb, ULONG __RPC_FAR *pcbRead) { m_is->Read((char *) pv, cb); if (pcbRead) *pcbRead = m_is->LastRead(); return S_OK; }; }; void wxIEHtmlWin::LoadUrl(const wxString& url) { VARIANTARG navFlag, targetFrame, postData, headers; navFlag.vt = VT_EMPTY; navFlag.vt = VT_I2; navFlag.iVal = navNoReadFromCache; targetFrame.vt = VT_EMPTY; postData.vt = VT_EMPTY; headers.vt = VT_EMPTY; HRESULT hret = 0; hret = m_webBrowser->Navigate((BSTR) (const wchar_t *) url.wc_str(wxConvUTF8), &navFlag, &targetFrame, &postData, &headers); }; class wxOwnedMemInputStream : public wxMemoryInputStream { public: char *m_data; wxOwnedMemInputStream(char *data, size_t len) : wxMemoryInputStream(data, len), m_data(data) {} ~wxOwnedMemInputStream() { free(m_data); } }; bool wxIEHtmlWin::LoadString(wxString html) { char *data = NULL; size_t len = html.length(); #ifdef UNICODE len *= 2; #endif data = (char *) malloc(len); memcpy(data, html.c_str(), len); return LoadStream(new wxOwnedMemInputStream(data, len)); }; bool wxIEHtmlWin::LoadStream(IStreamAdaptorBase *pstrm) { wxAutoOleInterface strm(pstrm); // Document Interface IDispatch *pDisp = NULL; HRESULT hret = m_webBrowser->get_Document(&pDisp); if (! pDisp) return false; wxAutoOleInterface disp(pDisp); // get IPersistStreamInit wxAutoOleInterface pPersistStreamInit(IID_IPersistStreamInit, disp); if (pPersistStreamInit.Ok()) { HRESULT hr = pPersistStreamInit->InitNew(); if (SUCCEEDED(hr)) hr = pPersistStreamInit->Load(strm); return SUCCEEDED(hr); } else return false; }; bool wxIEHtmlWin::LoadStream(istream *is) { // wrap reference around stream IStreamAdaptor *pstrm = new IStreamAdaptor(is); pstrm->AddRef(); return LoadStream(pstrm); }; bool wxIEHtmlWin::LoadStream(wxInputStream *is) { // wrap reference around stream IwxStreamAdaptor *pstrm = new IwxStreamAdaptor(is); pstrm->AddRef(); return LoadStream(pstrm); }; bool wxIEHtmlWin::GoBack() { HRESULT hret = 0; hret = m_webBrowser->GoBack(); return hret == S_OK; } bool wxIEHtmlWin::GoForward() { HRESULT hret = 0; hret = m_webBrowser->GoForward(); return hret == S_OK; } bool wxIEHtmlWin::GoHome() { HRESULT hret = 0; hret = m_webBrowser->GoHome(); return hret == S_OK; } bool wxIEHtmlWin::GoSearch() { HRESULT hret = 0; hret = m_webBrowser->GoSearch(); return hret == S_OK; } bool wxIEHtmlWin::Refresh(wxIEHtmlRefreshLevel level) { VARIANTARG levelArg; HRESULT hret = 0; levelArg.vt = VT_I2; levelArg.iVal = level; hret = m_webBrowser->Refresh2(&levelArg); return hret == S_OK; } bool wxIEHtmlWin::Stop() { HRESULT hret = 0; hret = m_webBrowser->Stop(); return hret == S_OK; } /////////////////////////////////////////////////////////////////////////////// static wxAutoOleInterface GetSelObject(IOleObject *oleObject) { // Query for IWebBrowser interface wxAutoOleInterface wb(IID_IWebBrowser2, oleObject); if (! wb.Ok()) return wxAutoOleInterface(); IDispatch *iDisp = NULL; HRESULT hr = wb->get_Document(&iDisp); if (hr != S_OK) return wxAutoOleInterface(); // Query for Document Interface wxAutoOleInterface hd(IID_IHTMLDocument2, iDisp); iDisp->Release(); if (! hd.Ok()) return wxAutoOleInterface(); IHTMLSelectionObject *_so = NULL; hr = hd->get_selection(&_so); // take ownership of selection object wxAutoOleInterface so(_so); return so; }; static wxAutoOleInterface GetSelRange(IOleObject *oleObject) { wxAutoOleInterface tr; wxAutoOleInterface so(GetSelObject(oleObject)); if (! so) return tr; IDispatch *iDisp = NULL; HRESULT hr = so->createRange(&iDisp); if (hr != S_OK) return tr; // Query for IHTMLTxtRange interface tr.QueryInterface(IID_IHTMLTxtRange, iDisp); iDisp->Release(); return tr; }; wxString wxIEHtmlWin::GetStringSelection(bool asHTML) { wxAutoOleInterface tr(GetSelRange(m_oleObject)); if (! tr) return wxEmptyString; BSTR text = NULL; HRESULT hr = E_FAIL; if (asHTML) hr = tr->get_htmlText(&text); else hr = tr->get_text(&text); if (hr != S_OK) return wxEmptyString; wxString s = text; SysFreeString(text); return s; }; wxString wxIEHtmlWin::GetText(bool asHTML) { if (! m_webBrowser.Ok()) return wxEmptyString; // get document dispatch interface IDispatch *iDisp = NULL; HRESULT hr = m_webBrowser->get_Document(&iDisp); if (hr != S_OK) return wxEmptyString; // Query for Document Interface wxAutoOleInterface hd(IID_IHTMLDocument2, iDisp); iDisp->Release(); if (! hd.Ok()) return wxEmptyString; // get body element IHTMLElement *_body = NULL; hd->get_body(&_body); if (! _body) return wxEmptyString; wxAutoOleInterface body(_body); // get inner text BSTR text = NULL; hr = E_FAIL; if (asHTML) hr = body->get_innerHTML(&text); else hr = body->get_innerText(&text); if (hr != S_OK) return wxEmptyString; wxString s = text; SysFreeString(text); return s; };