// MWebBrowser.cpp --- simple Win32 Web Browser // Copyright (C) 2019 Katayama Hirofumi MZ // This file is public domain software. #include "MWebBrowser.hpp" #include /*static*/ MWebBrowser * MWebBrowser::Create(HWND hwndParent) { MWebBrowser *pBrowser = new MWebBrowser(hwndParent); if (!pBrowser->IsCreated()) { pBrowser->Release(); pBrowser = NULL; } return pBrowser; } void JSObject::bindfunction(const std::wstring &funcname, functiontype function) { auto curr = DISPID_VALUE + 1 + funcnames.size(); funcnames[funcname] = curr; funcmap[curr] = function; } HRESULT STDMETHODCALLTYPE JSObject::QueryInterface(REFIID riid, void **ppv) { *ppv = NULL; if (riid == IID_IUnknown || riid == IID_IDispatch) { *ppv = static_cast(this); } if (*ppv != NULL) { AddRef(); return S_OK; } return E_NOINTERFACE; } ULONG STDMETHODCALLTYPE JSObject::AddRef() { return InterlockedIncrement(&ref); } ULONG STDMETHODCALLTYPE JSObject::Release() { int tmp = InterlockedDecrement(&ref); if (tmp == 0) { // OutputDebugString("JSObject::Release(): delete this"); delete this; } return tmp; } HRESULT STDMETHODCALLTYPE JSObject::GetTypeInfoCount(UINT *pctinfo) { *pctinfo = 0; return S_OK; } HRESULT STDMETHODCALLTYPE JSObject::GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo) { return E_FAIL; } HRESULT STDMETHODCALLTYPE JSObject::GetIDsOfNames(REFIID riid, LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId) { HRESULT hr = S_OK; for (UINT i = 0; i < cNames; i++) { auto iter = funcnames.find(rgszNames[i]); if (iter != funcnames.end()) { rgDispId[i] = iter->second; } else { rgDispId[i] = DISPID_UNKNOWN; hr = DISP_E_UNKNOWNNAME; } } return hr; } // https://github.com/Tobbe/CppIEEmbed HRESULT STDMETHODCALLTYPE JSObject::Invoke(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr) { if (wFlags & DISPATCH_METHOD) { HRESULT hr = S_OK; std::vector args; for (size_t i = 0; i < pDispParams->cArgs; ++i) { BSTR bstrArg = pDispParams->rgvarg[i].bstrVal; args.push_back(bstrArg); } if (funcmap.find(dispIdMember) == funcmap.end()) return DISP_E_MEMBERNOTFOUND; funcmap[dispIdMember](args.data(), args.size()); return S_OK; } return E_FAIL; } MWebBrowser::MWebBrowser(HWND hwndParent) : m_nRefCount(0), m_hwndParent(NULL), m_hwndCtrl(NULL), m_hwndIEServer(NULL), m_web_browser2(NULL), m_ole_object(NULL), m_ole_inplace_object(NULL), m_pDocHostUIHandler(NULL), m_hr(S_OK), m_bAllowInsecure(FALSE), m_nZoomPercents(100) { ::SetRectEmpty(&m_rc); m_hr = CreateBrowser(hwndParent); htmlSource = L""; IConnectionPointContainer *container = nullptr; m_web_browser2->QueryInterface(IID_IConnectionPointContainer, (void **)&container); container->FindConnectionPoint(__uuidof(DWebBrowserEvents2), &callback); IUnknown *punk = nullptr; QueryInterface(IID_IUnknown, (void **)&punk); callback->Advise(punk, &eventCookie); punk->Release(); container->Release(); jsobj = new JSObject(); jsobj->AddRef(); } BOOL MWebBrowser::IsCreated() const { return m_hr == S_OK; } MWebBrowser::~MWebBrowser() { if (m_pDocHostUIHandler) { m_pDocHostUIHandler->Release(); m_pDocHostUIHandler = NULL; } if (m_ole_object) { m_ole_object->Release(); m_ole_object = NULL; } if (m_ole_inplace_object) { m_ole_inplace_object->Release(); m_ole_inplace_object = NULL; } if (m_web_browser2) { m_web_browser2->Release(); m_web_browser2 = NULL; } if (jsobj) { jsobj->Release(); delete jsobj; jsobj = NULL; } } IWebBrowser2 *MWebBrowser::GetIWebBrowser2() { return m_web_browser2; } IHTMLDocument2 *MWebBrowser::GetIHTMLDocument2() { IDispatch *pDisp; m_web_browser2->get_Document(&pDisp); if (pDisp) { return static_cast(pDisp); } return NULL; } HWND MWebBrowser::GetControlWindow() { if (::IsWindow(m_hwndCtrl)) return m_hwndCtrl; if (!m_ole_inplace_object) return NULL; m_ole_inplace_object->GetWindow(&m_hwndCtrl); return m_hwndCtrl; } HWND MWebBrowser::GetIEServerWindow() { if (::IsWindow(m_hwndIEServer)) return m_hwndIEServer; HWND hwnd = ::GetWindow(m_hwndParent, GW_CHILD); while (hwnd) { WCHAR szClass[64]; ::GetClassNameW(hwnd, szClass, 64); if (lstrcmpiW(szClass, L"Internet Explorer_Server") == 0) { m_hwndIEServer = hwnd; return hwnd; } hwnd = ::GetWindow(hwnd, GW_CHILD); } return NULL; } HRESULT MWebBrowser::CreateBrowser(HWND hwndParent) { m_hwndParent = hwndParent; HRESULT hr; hr = ::OleCreate(CLSID_WebBrowser, IID_IOleObject, OLERENDER_DRAW, NULL, this, this, (void **)&m_ole_object); if (FAILED(hr)) { assert(0); return hr; } if (m_pDocHostUIHandler) { m_pDocHostUIHandler->Release(); m_pDocHostUIHandler = NULL; } m_ole_object->QueryInterface(&m_pDocHostUIHandler); hr = m_ole_object->SetClientSite(this); if (FAILED(hr)) { assert(0); return hr; } hr = ::OleSetContainedObject(m_ole_object, TRUE); if (FAILED(hr)) { assert(0); return hr; } RECT rc; ::SetRectEmpty(&rc); hr = m_ole_object->DoVerb(OLEIVERB_INPLACEACTIVATE, NULL, this, 0, m_hwndParent, &rc); if (FAILED(hr)) { assert(0); return hr; } hr = m_ole_object->QueryInterface(&m_web_browser2); if (FAILED(hr)) { assert(0); return hr; } HWND hwnd = GetControlWindow(); DWORD exstyle = GetWindowLong(hwnd, GWL_EXSTYLE); SetWindowLong(hwnd, GWL_EXSTYLE, exstyle | WS_EX_CLIENTEDGE); ShowWindow(hwnd, SW_SHOWNORMAL); Release(); return S_OK; } void MWebBrowser::Destroy() { if (m_web_browser2) m_web_browser2->Quit(); m_hwndParent = NULL; m_hwndCtrl = NULL; m_hwndIEServer = NULL; } RECT MWebBrowser::PixelToHIMETRIC(const RECT &rc) { HDC hDC = ::GetDC(NULL); INT nPixelsPerInchX = ::GetDeviceCaps(hDC, LOGPIXELSX); INT nPixelsPerInchY = ::GetDeviceCaps(hDC, LOGPIXELSY); RECT ret; ret.left = MulDiv(rc.left, 2540, nPixelsPerInchX); ret.top = MulDiv(rc.top, 2540, nPixelsPerInchY); ret.right = MulDiv(rc.right, 2540, nPixelsPerInchX); ret.bottom = MulDiv(rc.bottom, 2540, nPixelsPerInchY); ::ReleaseDC(NULL, hDC); return ret; } void MWebBrowser::MoveWindow(const RECT &rc) { m_rc = rc; SIZEL siz; RECT rcHIMETRIC = PixelToHIMETRIC(rc); siz.cx = rcHIMETRIC.right - rcHIMETRIC.left; siz.cy = rcHIMETRIC.bottom - rcHIMETRIC.top; m_ole_object->SetExtent(DVASPECT_CONTENT, &siz); if (m_ole_inplace_object) { m_ole_inplace_object->SetObjectRects(&m_rc, &m_rc); } } void MWebBrowser::GoHome() { if (m_web_browser2) m_web_browser2->GoHome(); } void MWebBrowser::GoBack() { if (m_web_browser2) m_web_browser2->GoBack(); } void MWebBrowser::GoForward() { if (m_web_browser2) m_web_browser2->GoForward(); } void MWebBrowser::Stop() { if (m_web_browser2) m_web_browser2->Stop(); } void MWebBrowser::StopDownload() { if (!m_web_browser2) return; IDispatch *pDisp; m_web_browser2->get_Document(&pDisp); if (pDisp) { IOleCommandTarget *pCmdTarget = NULL; pDisp->QueryInterface(&pCmdTarget); if (pCmdTarget) { OLECMDEXECOPT option = OLECMDEXECOPT_DONTPROMPTUSER; pCmdTarget->Exec(NULL, OLECMDID_STOPDOWNLOAD, option, NULL, NULL); pCmdTarget->Release(); } pDisp->Release(); } } void MWebBrowser::Refresh() { if (m_web_browser2) m_web_browser2->Refresh(); } HRESULT MWebBrowser::Navigate(const WCHAR *url) { HRESULT hr = E_FAIL; if (m_web_browser2) { bstr_t bstrURL(url); variant_t flags(0); hr = m_web_browser2->Navigate(bstrURL, &flags, 0, 0, 0); } return hr; } HRESULT MWebBrowser::Navigate2(const WCHAR *url, DWORD dwFlags) { HRESULT hr = E_FAIL; if (!m_web_browser2) { return hr; } VARIANT var1, var2, varEmpty; VariantInit(&var1); VariantInit(&var2); VariantInit(&varEmpty); V_VT(&var1) = VT_BSTR; V_BSTR(&var1) = SysAllocString(url); V_VT(&var2) = VT_I4; V_I4(&var2) = dwFlags; V_VT(&varEmpty) = VT_EMPTY; hr = m_web_browser2->Navigate2(&var1, &var2, &varEmpty, &varEmpty, &varEmpty); VariantClear(&var1); VariantClear(&var2); VariantClear(&varEmpty); return hr; } void MWebBrowser::Print(BOOL bBang) { if (!m_web_browser2) return; IDispatch *pDisp; m_web_browser2->get_Document(&pDisp); if (pDisp) { IOleCommandTarget *pCmdTarget = NULL; pDisp->QueryInterface(&pCmdTarget); if (pCmdTarget) { OLECMDEXECOPT option; if (bBang) option = OLECMDEXECOPT_DONTPROMPTUSER; else option = OLECMDEXECOPT_PROMPTUSER; pCmdTarget->Exec(NULL, OLECMDID_PRINT, option, NULL, NULL); pCmdTarget->Release(); } pDisp->Release(); } } void MWebBrowser::PrintPreview() { if (!m_web_browser2) return; IDispatch *pDisp; m_web_browser2->get_Document(&pDisp); if (pDisp) { IOleCommandTarget *pCmdTarget = NULL; pDisp->QueryInterface(&pCmdTarget); if (pCmdTarget) { OLECMDEXECOPT option = OLECMDEXECOPT_DONTPROMPTUSER; pCmdTarget->Exec(NULL, OLECMDID_PRINTPREVIEW, option, NULL, NULL); pCmdTarget->Release(); } pDisp->Release(); } } void MWebBrowser::PageSetup() { if (!m_web_browser2) return; IDispatch *pDisp; m_web_browser2->get_Document(&pDisp); if (pDisp) { IOleCommandTarget *pCmdTarget = NULL; pDisp->QueryInterface(&pCmdTarget); if (pCmdTarget) { OLECMDEXECOPT option = OLECMDEXECOPT_DONTPROMPTUSER; pCmdTarget->Exec(NULL, OLECMDID_PAGESETUP, option, NULL, NULL); pCmdTarget->Release(); } pDisp->Release(); } } BOOL MWebBrowser::TranslateAccelerator(LPMSG pMsg) { if (!m_web_browser2) return FALSE; IOleInPlaceActiveObject *pOIPAO = NULL; HRESULT hr = m_web_browser2->QueryInterface(&pOIPAO); if (SUCCEEDED(hr)) { hr = pOIPAO->TranslateAccelerator(pMsg); pOIPAO->Release(); return hr == S_OK; } return FALSE; } HRESULT MWebBrowser::get_LocationURL(BSTR *bstrURL) const { if (!m_web_browser2) { *bstrURL = NULL; return E_FAIL; } return m_web_browser2->get_LocationURL(bstrURL); } HRESULT MWebBrowser::get_mimeType(BSTR *bstrMIME) const { if (!m_web_browser2) { *bstrMIME = NULL; return E_FAIL; } HRESULT hr = E_FAIL; IDispatch *pDisp; m_web_browser2->get_Document(&pDisp); if (pDisp) { IHTMLDocument2 *pDocument = static_cast(pDisp); hr = pDocument->get_mimeType(bstrMIME); pDisp->Release(); } return hr; } BOOL MWebBrowser::is_busy() const { if (!m_web_browser2) { return FALSE; } VARIANT_BOOL b = FALSE; m_web_browser2->get_Busy(&b); return b; } HRESULT MWebBrowser::get_Application(IDispatch **ppApplication) const { *ppApplication = NULL; if (!m_web_browser2) return E_NOINTERFACE; return m_web_browser2->get_Application(ppApplication); } void MWebBrowser::AllowInsecure(BOOL bAllow) { m_bAllowInsecure = bAllow; } HRESULT MWebBrowser::put_Silent(VARIANT_BOOL bSilent) { if (!m_web_browser2) return E_NOINTERFACE; return m_web_browser2->put_Silent(bSilent); } HRESULT MWebBrowser::ZoomUp() { LONG percents = m_nZoomPercents; if (percents >= 300) return E_FAIL; if (percents < 100) { percents += 10; } else { percents += 50; } return ZoomPercents(percents); } HRESULT MWebBrowser::ZoomDown() { LONG percents = m_nZoomPercents; if (percents <= 50) return E_FAIL; if (percents > 100) { percents -= 50; } else { percents -= 10; } return ZoomPercents(percents); } HRESULT MWebBrowser::Zoom100() { return ZoomPercents(100); } HRESULT MWebBrowser::ZoomPercents(LONG percents) { VARIANT zoom; VariantInit(&zoom); V_VT(&zoom) = VT_I4; V_I4(&zoom) = percents; OLECMDEXECOPT option = OLECMDEXECOPT_DONTPROMPTUSER; HRESULT hr = m_web_browser2->ExecWB(OLECMDID_OPTICAL_ZOOM, option, &zoom, NULL); if (SUCCEEDED(hr)) { m_nZoomPercents = percents; } return hr; } // IUnknown interface STDMETHODIMP MWebBrowser::QueryInterface(REFIID riid, void **ppvObj) { if (riid == __uuidof(IUnknown)) { *ppvObj = static_cast(this); } else if (riid == __uuidof(IOleInPlaceSite)) { *ppvObj = static_cast(this); } else if (riid == __uuidof(IServiceProvider)) { *ppvObj = static_cast(this); } else if (riid == __uuidof(IDocHostUIHandler)) { *ppvObj = static_cast(this); } else if (riid == __uuidof(IDispatch)) *ppvObj = static_cast(this); else if (riid == __uuidof(IOleClientSite)) *ppvObj = static_cast(this); else { return E_NOINTERFACE; } AddRef(); return S_OK; } STDMETHODIMP_(ULONG) MWebBrowser::AddRef() { m_nRefCount++; return m_nRefCount; } STDMETHODIMP_(ULONG) MWebBrowser::Release() { --m_nRefCount; if (m_nRefCount != 0) return m_nRefCount; delete this; return 0; } // IOleWindow interface STDMETHODIMP MWebBrowser::GetWindow(HWND *phwnd) { *phwnd = m_hwndParent; return S_OK; } STDMETHODIMP MWebBrowser::ContextSensitiveHelp(BOOL fEnterMode) { return E_NOTIMPL; } // IOleInPlaceSite interface STDMETHODIMP MWebBrowser::CanInPlaceActivate() { return S_OK; } STDMETHODIMP MWebBrowser::OnInPlaceActivate() { ::OleLockRunning(m_ole_object, TRUE, FALSE); m_ole_object->QueryInterface(&m_ole_inplace_object); m_ole_inplace_object->SetObjectRects(&m_rc, &m_rc); return S_OK; } STDMETHODIMP MWebBrowser::OnUIActivate() { return S_OK; } STDMETHODIMP MWebBrowser::GetWindowContext( IOleInPlaceFrame **ppFrame, IOleInPlaceUIWindow **ppDoc, LPRECT lprcPosRect, LPRECT lprcClipRect, LPOLEINPLACEFRAMEINFO lpFrameInfo) { *ppFrame = NULL; *ppDoc = NULL; *lprcPosRect = m_rc; *lprcClipRect = *lprcPosRect; lpFrameInfo->fMDIApp = FALSE; lpFrameInfo->hwndFrame = m_hwndParent; lpFrameInfo->haccel = NULL; lpFrameInfo->cAccelEntries = 0; return S_OK; } STDMETHODIMP MWebBrowser::Scroll(SIZE scrollExtant) { return E_NOTIMPL; } STDMETHODIMP MWebBrowser::OnUIDeactivate(BOOL fUndoable) { return S_OK; } STDMETHODIMP MWebBrowser::OnInPlaceDeactivate() { m_hwndCtrl = NULL; m_ole_inplace_object = NULL; return S_OK; } STDMETHODIMP MWebBrowser::DiscardUndoState() { return E_NOTIMPL; } STDMETHODIMP MWebBrowser::DeactivateAndUndo() { return E_NOTIMPL; } STDMETHODIMP MWebBrowser::OnPosRectChange(LPCRECT lprcPosRect) { return E_NOTIMPL; } // IOleClientSite interface STDMETHODIMP MWebBrowser::SaveObject() { return E_NOTIMPL; } STDMETHODIMP MWebBrowser::GetMoniker( DWORD dwAssign, DWORD dwWhichMoniker, IMoniker **ppmk) { if (dwAssign == OLEGETMONIKER_ONLYIFTHERE && dwWhichMoniker == OLEWHICHMK_CONTAINER) { return E_FAIL; } return E_NOTIMPL; } STDMETHODIMP MWebBrowser::GetContainer(IOleContainer **ppContainer) { return E_NOINTERFACE; } STDMETHODIMP MWebBrowser::ShowObject() { return S_OK; } STDMETHODIMP MWebBrowser::OnShowWindow(BOOL fShow) { return S_OK; } STDMETHODIMP MWebBrowser::RequestNewObjectLayout() { return E_NOTIMPL; } // IStorage interface STDMETHODIMP MWebBrowser::CreateStream( const OLECHAR *pwcsName, DWORD grfMode, DWORD reserved1, DWORD reserved2, IStream **ppstm) { return E_NOTIMPL; } STDMETHODIMP MWebBrowser::OpenStream( const OLECHAR *pwcsName, void *reserved1, DWORD grfMode, DWORD reserved2, IStream **ppstm) { return E_NOTIMPL; } STDMETHODIMP MWebBrowser::CreateStorage( const OLECHAR *pwcsName, DWORD grfMode, DWORD reserved1, DWORD reserved2, IStorage **ppstg) { return E_NOTIMPL; } STDMETHODIMP MWebBrowser::OpenStorage( const OLECHAR *pwcsName, IStorage *pstgPriority, DWORD grfMode, SNB snbExclude, DWORD reserved, IStorage **ppstg) { return E_NOTIMPL; } STDMETHODIMP MWebBrowser::CopyTo( DWORD ciidExclude, const IID *rgiidExclude, SNB snbExclude, IStorage *pstgDest) { return E_NOTIMPL; } STDMETHODIMP MWebBrowser::MoveElementTo( const OLECHAR *pwcsName, IStorage *pstgDest, const OLECHAR *pwcsNewName, DWORD grfFlags) { return E_NOTIMPL; } STDMETHODIMP MWebBrowser::Commit(DWORD grfCommitFlags) { return E_NOTIMPL; } STDMETHODIMP MWebBrowser::Revert() { return E_NOTIMPL; } STDMETHODIMP MWebBrowser::EnumElements( DWORD reserved1, void *reserved2, DWORD reserved3, IEnumSTATSTG **ppenum) { return E_NOTIMPL; } STDMETHODIMP MWebBrowser::DestroyElement( const OLECHAR *pwcsName) { return E_NOTIMPL; } STDMETHODIMP MWebBrowser::RenameElement( const OLECHAR *pwcsOldName, const OLECHAR *pwcsNewName) { return E_NOTIMPL; } STDMETHODIMP MWebBrowser::SetElementTimes( const OLECHAR *pwcsName, const FILETIME *pctime, const FILETIME *patime, const FILETIME *pmtime) { return E_NOTIMPL; } STDMETHODIMP MWebBrowser::SetClass(REFCLSID clsid) { return S_OK; } STDMETHODIMP MWebBrowser::SetStateBits(DWORD grfStateBits, DWORD grfMask) { return E_NOTIMPL; } STDMETHODIMP MWebBrowser::Stat(STATSTG *pstatstg, DWORD grfStatFlag) { return E_NOTIMPL; } // IServiceProvider interface STDMETHODIMP MWebBrowser::QueryService( REFGUID guidService, REFIID riid, void **ppvObject) { *ppvObject = NULL; if (riid == __uuidof(IWindowForBindingUI) || riid == __uuidof(IHttpSecurity)) { *ppvObject = static_cast(this); } else { return E_NOTIMPL; } AddRef(); return S_OK; } // IWindowForBindingUI interface STDMETHODIMP MWebBrowser::GetWindow(REFGUID rguidReason, HWND *phwnd) { *phwnd = m_hwndParent; return S_OK; } STDMETHODIMP MWebBrowser::OnSecurityProblem(DWORD dwProblem) { printf("MWebBrowser::OnSecurityProblem\n"); BSTR url = NULL; get_LocationURL(&url); if (url) { SysFreeString(url); } { return S_OK; } { return S_OK; } return E_ABORT; } // IDocHostUIHandler interface STDMETHODIMP MWebBrowser::ShowContextMenu( DWORD dwID, POINT *ppt, IUnknown *pcmdtReserved, IDispatch *pdispReserved) { return S_FALSE; } STDMETHODIMP MWebBrowser::GetHostInfo(DOCHOSTUIINFO *pInfo) { if (m_pDocHostUIHandler) return m_pDocHostUIHandler->GetHostInfo(pInfo); return E_NOTIMPL; } STDMETHODIMP MWebBrowser::ShowUI( DWORD dwID, IOleInPlaceActiveObject *pActiveObject, IOleCommandTarget *pCommandTarget, IOleInPlaceFrame *pFrame, IOleInPlaceUIWindow *pDoc) { if (m_pDocHostUIHandler) return m_pDocHostUIHandler->ShowUI(dwID, pActiveObject, pCommandTarget, pFrame, pDoc); return E_NOTIMPL; } STDMETHODIMP MWebBrowser::HideUI() { if (m_pDocHostUIHandler) return m_pDocHostUIHandler->HideUI(); return E_NOTIMPL; } STDMETHODIMP MWebBrowser::UpdateUI() { if (m_pDocHostUIHandler) return m_pDocHostUIHandler->UpdateUI(); return E_NOTIMPL; } STDMETHODIMP MWebBrowser::EnableModeless(BOOL fEnable) { if (m_pDocHostUIHandler) return m_pDocHostUIHandler->EnableModeless(fEnable); return E_NOTIMPL; } STDMETHODIMP MWebBrowser::OnDocWindowActivate(BOOL fActivate) { if (m_pDocHostUIHandler) return m_pDocHostUIHandler->OnDocWindowActivate(fActivate); return E_NOTIMPL; } STDMETHODIMP MWebBrowser::OnFrameWindowActivate(BOOL fActivate) { if (m_pDocHostUIHandler) return m_pDocHostUIHandler->OnFrameWindowActivate(fActivate); return E_NOTIMPL; } STDMETHODIMP MWebBrowser::ResizeBorder( LPCRECT prcBorder, IOleInPlaceUIWindow *pUIWindow, BOOL fRameWindow) { if (m_pDocHostUIHandler) return m_pDocHostUIHandler->ResizeBorder(prcBorder, pUIWindow, fRameWindow); return E_NOTIMPL; } STDMETHODIMP MWebBrowser::TranslateAccelerator( LPMSG lpMsg, const GUID *pguidCmdGroup, DWORD nCmdID) { return S_FALSE; } STDMETHODIMP MWebBrowser::GetOptionKeyPath(LPOLESTR *pchKey, DWORD dw) { return S_FALSE; } STDMETHODIMP MWebBrowser::GetDropTarget( IDropTarget *pDropTarget, IDropTarget **ppDropTarget) { *ppDropTarget = NULL; return E_NOTIMPL; } STDMETHODIMP MWebBrowser::GetExternal(IDispatch **ppDispatch) { *ppDispatch = NULL; return E_NOTIMPL; } STDMETHODIMP MWebBrowser::TranslateUrl( DWORD dwTranslate, OLECHAR *pchURLIn, OLECHAR **ppchURLOut) { *ppchURLOut = NULL; return S_FALSE; } STDMETHODIMP MWebBrowser::FilterDataObject(IDataObject *pDO, IDataObject **ppDORet) { *ppDORet = NULL; return S_FALSE; } HRESULT MWebBrowser::Quit() { if (!m_web_browser2) return E_NOINTERFACE; return m_web_browser2->Quit(); } HRESULT MWebBrowser::GetTypeInfoCount(UINT *pctinfo) { return E_FAIL; } HRESULT MWebBrowser::GetTypeInfo(UINT, LCID, ITypeInfo **) { return E_FAIL; } HRESULT MWebBrowser::GetIDsOfNames(REFIID riid, LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId) { return E_FAIL; } void AddCustomObject(IHTMLDocument2 *doc, IDispatch *custObj, std::string name) { if (doc == NULL) { return; } IHTMLWindow2 *win = NULL; doc->get_parentWindow(&win); doc->Release(); if (win == NULL) { return; } IDispatchEx *winEx; win->QueryInterface(&winEx); win->Release(); if (winEx == NULL) { return; } int lenW = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, name.c_str(), -1, NULL, 0); BSTR objName = SysAllocStringLen(0, lenW); MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, name.c_str(), -1, objName, lenW); DISPID dispid; HRESULT hr = winEx->GetDispID(objName, fdexNameEnsure, &dispid); SysFreeString(objName); if (FAILED(hr)) { return; } DISPID namedArgs[] = {DISPID_PROPERTYPUT}; DISPPARAMS params; params.rgvarg = new VARIANT[1]; params.rgvarg[0].pdispVal = custObj; params.rgvarg[0].vt = VT_DISPATCH; params.rgdispidNamedArgs = namedArgs; params.cArgs = 1; params.cNamedArgs = 1; hr = winEx->InvokeEx(dispid, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYPUT, ¶ms, NULL, NULL, NULL); winEx->Release(); if (FAILED(hr)) { return; } } HRESULT MWebBrowser::Invoke(DISPID dispIdMember, REFIID, LCID, WORD, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *, UINT *) { if (dispIdMember == DISPID_DOCUMENTCOMPLETE) return OnCompleted(pDispParams); else if (dispIdMember == DISPID_NAVIGATECOMPLETE2) return AddCustomObject(GetIHTMLDocument2(), jsobj, "LUNAJSObject"), S_OK; else return S_OK; } HRESULT MWebBrowser::OnCompleted(DISPPARAMS *args) { HRESULT hr; IDispatch *pDispatch = 0; IHTMLDocument2 *pHtmlDoc2 = 0; IPersistStreamInit *pPSI = 0; IStream *pStream = 0; HGLOBAL hHTMLContent; if (htmlSource.empty()) return S_OK; hr = m_web_browser2->get_Document(&pDispatch); if (SUCCEEDED(hr) && pDispatch) hr = pDispatch->QueryInterface(IID_IHTMLDocument2, (void **)&pHtmlDoc2); if (SUCCEEDED(hr) && pHtmlDoc2) hr = pHtmlDoc2->QueryInterface(IID_IPersistStreamInit, (void **)&pPSI); // allocate global memory to copy the HTML content to hHTMLContent = ::GlobalAlloc(GMEM_MOVEABLE, (htmlSource.size() + 1) * sizeof(TCHAR)); if (hHTMLContent) { wchar_t *p_content(static_cast(GlobalLock(hHTMLContent))); ::wcscpy(p_content, htmlSource.c_str()); GlobalUnlock(hHTMLContent); // create a stream object based on the HTML content if (SUCCEEDED(hr) && pPSI) hr = ::CreateStreamOnHGlobal(hHTMLContent, TRUE, &pStream); if (SUCCEEDED(hr) && pStream) hr = pPSI->InitNew(); if (SUCCEEDED(hr)) hr = pPSI->Load(pStream); } if (pStream) pStream->Release(); if (pPSI) pPSI->Release(); if (pHtmlDoc2) pHtmlDoc2->Release(); if (pDispatch) pDispatch->Release(); htmlSource = L""; return S_OK; } HRESULT MWebBrowser::SetHtml(const wchar_t *html) { htmlSource = html; Navigate(L"about:blank"); return S_OK; }