1 // This Source Code Form is subject to the terms of the Mozilla Public
2 // License, v. 2.0.If a copy of the MPL was not distributed with this
3 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
4 
5 #include "WebBrowser.h"
6 #include <mshtmdid.h>
7 
WebBrowser(HWND _hWndParent)8 WebBrowser::WebBrowser(HWND _hWndParent) : mHwndParent(_hWndParent) {
9   // Whatever executed this constructor owns our first reference.
10   AddRef();
11 
12   HRESULT hr = ::OleCreate(CLSID_WebBrowser, IID_IOleObject, OLERENDER_DRAW, 0,
13                            this, this, (void**)&mOleObject);
14   if (FAILED(hr)) {
15     return;
16   }
17 
18   RECT posRect;
19   ::GetClientRect(mHwndParent, &posRect);
20 
21   hr = mOleObject->DoVerb(OLEIVERB_INPLACEACTIVATE, nullptr, this, 0,
22                           mHwndParent, &posRect);
23   if (FAILED(hr)) {
24     mOleObject->Release();
25     mOleObject = nullptr;
26     return;
27   }
28 
29   SetRect(posRect);
30 
31   hr = mOleObject->QueryInterface(&mWebBrowser2);
32   if (FAILED(hr)) {
33     mOleObject->Release();
34     mOleObject = nullptr;
35     return;
36   }
37 
38   mWebBrowser2->put_Silent(VARIANT_TRUE);
39 }
40 
~WebBrowser()41 WebBrowser::~WebBrowser() {
42   if (mWebBrowser2) {
43     mWebBrowser2->Release();
44     mWebBrowser2 = nullptr;
45   }
46   if (mOleInPlaceActiveObject) {
47     mOleInPlaceActiveObject->Release();
48     mOleInPlaceActiveObject = nullptr;
49   }
50   if (mOleInPlaceObject) {
51     mOleInPlaceObject->Release();
52     mOleInPlaceObject = nullptr;
53   }
54   if (mOleObject) {
55     mOleObject->Release();
56     mOleObject = nullptr;
57   }
58 }
59 
Shutdown()60 void WebBrowser::Shutdown() {
61   if (mOleObject) {
62     mOleObject->Close(OLECLOSE_NOSAVE);
63     mOleObject->SetClientSite(nullptr);
64   }
65 }
66 
IsInitialized()67 bool WebBrowser::IsInitialized() { return mOleObject != nullptr; }
68 
ActiveObjectTranslateAccelerator(bool tab,LPMSG lpmsg)69 HRESULT WebBrowser::ActiveObjectTranslateAccelerator(bool tab, LPMSG lpmsg) {
70   if (IsInitialized() && mOleInPlaceActiveObject) {
71     HRESULT hr = mOleInPlaceActiveObject->TranslateAcceleratorW(lpmsg);
72     if (hr == S_FALSE && tab) {
73       // The browser control will give up focus, but it is the only control so
74       // it would get focus again via IsDialogMessage. This does not result in
75       // the focus returning to the web page, though, so instead let the
76       // control process the tab again.
77       hr = mOleInPlaceActiveObject->TranslateAcceleratorW(lpmsg);
78     }
79     return hr;
80   } else {
81     return S_FALSE;
82   }
83 }
84 
SetRect(const RECT & _rc)85 void WebBrowser::SetRect(const RECT& _rc) {
86   mRect = _rc;
87 
88   if (mOleInPlaceObject) {
89     mOleInPlaceObject->SetObjectRects(&mRect, &mRect);
90   }
91 }
92 
Resize(DWORD width,DWORD height)93 void WebBrowser::Resize(DWORD width, DWORD height) {
94   RECT r = mRect;
95   r.bottom = r.top + height;
96   r.right = r.left + width;
97   SetRect(r);
98 }
99 
Navigate(wchar_t * url)100 void WebBrowser::Navigate(wchar_t* url) {
101   if (!IsInitialized()) {
102     return;
103   }
104 
105   VARIANT flags;
106   VariantInit(&flags);
107   flags.vt = VT_I4;
108   flags.intVal = navNoHistory | navEnforceRestricted | navUntrustedForDownload |
109                  navBlockRedirectsXDomain;
110 
111   mWebBrowser2->Navigate(url, &flags, nullptr, nullptr, nullptr);
112 }
113 
AddCustomFunction(wchar_t * name,CustomFunction function,void * arg)114 void WebBrowser::AddCustomFunction(wchar_t* name, CustomFunction function,
115                                    void* arg) {
116   CustomFunctionRecord record = {name, function, arg};
117 
118 // We've disabled exceptions but push_back can throw on an allocation
119 // failure, so we need to suppress a warning trying to tell us that
120 // that combination doesn't make any sense.
121 #pragma warning(suppress : 4530)
122   mCustomFunctions.push_back(record);
123 }
124 
125 //////////////////////////////////////////////////////////////////////////////
126 // IUnknown
127 //////////////////////////////////////////////////////////////////////////////
128 // This is a standard IUnknown implementation, we don't need anything special.
129 
QueryInterface(REFIID riid,void ** ppvObject)130 HRESULT STDMETHODCALLTYPE WebBrowser::QueryInterface(REFIID riid,
131                                                      void** ppvObject) {
132   if (riid == __uuidof(IUnknown)) {
133     *ppvObject = static_cast<IOleClientSite*>(this);
134   } else if (riid == __uuidof(IOleClientSite)) {
135     *ppvObject = static_cast<IOleClientSite*>(this);
136   } else if (riid == __uuidof(IOleInPlaceSite)) {
137     *ppvObject = static_cast<IOleInPlaceSite*>(this);
138   } else if (riid == __uuidof(IDropTarget)) {
139     *ppvObject = static_cast<IDropTarget*>(this);
140   } else if (riid == __uuidof(IStorage)) {
141     *ppvObject = static_cast<IStorage*>(this);
142   } else if (riid == __uuidof(IDocHostUIHandler)) {
143     *ppvObject = static_cast<IDocHostUIHandler*>(this);
144   } else if (riid == __uuidof(IDocHostShowUI)) {
145     *ppvObject = static_cast<IDocHostShowUI*>(this);
146   } else if (riid == __uuidof(IDispatch)) {
147     *ppvObject = static_cast<IDispatch*>(this);
148   } else {
149     *ppvObject = nullptr;
150     return E_NOINTERFACE;
151   }
152 
153   AddRef();
154   return S_OK;
155 }
156 
AddRef()157 ULONG STDMETHODCALLTYPE WebBrowser::AddRef() {
158   return InterlockedIncrement(&mComRefCount);
159 }
160 
Release()161 ULONG STDMETHODCALLTYPE WebBrowser::Release() {
162   ULONG refCount = InterlockedDecrement(&mComRefCount);
163   if (refCount == 0) {
164     delete this;
165   }
166   return refCount;
167 }
168 
169 //////////////////////////////////////////////////////////////////////////////
170 // IOleWindow
171 //////////////////////////////////////////////////////////////////////////////
172 
173 HRESULT STDMETHODCALLTYPE
GetWindow(__RPC__deref_out_opt HWND * phwnd)174 WebBrowser::GetWindow(__RPC__deref_out_opt HWND* phwnd) {
175   *phwnd = mHwndParent;
176   return S_OK;
177 }
178 
ContextSensitiveHelp(BOOL fEnterMode)179 HRESULT STDMETHODCALLTYPE WebBrowser::ContextSensitiveHelp(BOOL fEnterMode) {
180   // We don't provide context-sensitive help.
181   return E_NOTIMPL;
182 }
183 
184 //////////////////////////////////////////////////////////////////////////////
185 // IOleInPlaceSite
186 //////////////////////////////////////////////////////////////////////////////
187 
CanInPlaceActivate()188 HRESULT STDMETHODCALLTYPE WebBrowser::CanInPlaceActivate() {
189   // We always support in-place activation.
190   return S_OK;
191 }
192 
OnInPlaceActivate()193 HRESULT STDMETHODCALLTYPE WebBrowser::OnInPlaceActivate() {
194   OleLockRunning(mOleObject, TRUE, FALSE);
195   mOleObject->QueryInterface(&mOleInPlaceObject);
196   mOleInPlaceObject->QueryInterface(&mOleInPlaceActiveObject);
197   mOleInPlaceObject->SetObjectRects(&mRect, &mRect);
198 
199   return S_OK;
200 }
201 
OnUIActivate()202 HRESULT STDMETHODCALLTYPE WebBrowser::OnUIActivate() {
203   // Nothing to do before activating the control's UI.
204   return S_OK;
205 }
206 
GetWindowContext(__RPC__deref_out_opt IOleInPlaceFrame ** ppFrame,__RPC__deref_out_opt IOleInPlaceUIWindow ** ppDoc,__RPC__out LPRECT lprcPosRect,__RPC__out LPRECT lprcClipRect,__RPC__inout LPOLEINPLACEFRAMEINFO lpFrameInfo)207 HRESULT STDMETHODCALLTYPE WebBrowser::GetWindowContext(
208     __RPC__deref_out_opt IOleInPlaceFrame** ppFrame,
209     __RPC__deref_out_opt IOleInPlaceUIWindow** ppDoc,
210     __RPC__out LPRECT lprcPosRect, __RPC__out LPRECT lprcClipRect,
211     __RPC__inout LPOLEINPLACEFRAMEINFO lpFrameInfo) {
212   *ppFrame = nullptr;
213   *ppDoc = nullptr;
214   *lprcPosRect = mRect;
215   *lprcClipRect = mRect;
216 
217   lpFrameInfo->fMDIApp = false;
218   lpFrameInfo->hwndFrame = mHwndParent;
219   lpFrameInfo->haccel = nullptr;
220   lpFrameInfo->cAccelEntries = 0;
221 
222   return S_OK;
223 }
224 
Scroll(SIZE scrollExtant)225 HRESULT STDMETHODCALLTYPE WebBrowser::Scroll(SIZE scrollExtant) {
226   // We should have disabled all scrollbars.
227   return E_NOTIMPL;
228 }
229 
OnUIDeactivate(BOOL fUndoable)230 HRESULT STDMETHODCALLTYPE WebBrowser::OnUIDeactivate(BOOL fUndoable) {
231   // Nothing to do after deactivating the control's UI.
232   return S_OK;
233 }
234 
OnInPlaceDeactivate()235 HRESULT STDMETHODCALLTYPE WebBrowser::OnInPlaceDeactivate() {
236   if (mOleInPlaceObject) {
237     mOleInPlaceObject->Release();
238     mOleInPlaceObject = nullptr;
239   }
240 
241   return S_OK;
242 }
243 
244 // We don't support the concept of undo.
DiscardUndoState()245 HRESULT STDMETHODCALLTYPE WebBrowser::DiscardUndoState() { return E_NOTIMPL; }
246 
DeactivateAndUndo()247 HRESULT STDMETHODCALLTYPE WebBrowser::DeactivateAndUndo() { return E_NOTIMPL; }
248 
249 // We don't support moving or resizing the control.
250 HRESULT STDMETHODCALLTYPE
OnPosRectChange(__RPC__in LPCRECT lprcPosRect)251 WebBrowser::OnPosRectChange(__RPC__in LPCRECT lprcPosRect) {
252   return E_NOTIMPL;
253 }
254 
255 //////////////////////////////////////////////////////////////////////////////
256 // IOleClientSite
257 //////////////////////////////////////////////////////////////////////////////
258 // We don't need anything that IOleClientSite does, because we're doing OLE
259 // only in the most basic sense and we don't support linking (or, indeed,
260 // embedding), but some implementation of this interface is required for
261 // OleCreate to work, so we have to have a stub version.
262 
SaveObject()263 HRESULT STDMETHODCALLTYPE WebBrowser::SaveObject() { return E_NOTIMPL; }
264 
265 HRESULT STDMETHODCALLTYPE
GetMoniker(DWORD dwAssign,DWORD dwWhichMoniker,__RPC__deref_out_opt IMoniker ** ppmk)266 WebBrowser::GetMoniker(DWORD dwAssign, DWORD dwWhichMoniker,
267                        __RPC__deref_out_opt IMoniker** ppmk) {
268   return E_NOTIMPL;
269 }
270 
271 HRESULT STDMETHODCALLTYPE
GetContainer(__RPC__deref_out_opt IOleContainer ** ppContainer)272 WebBrowser::GetContainer(__RPC__deref_out_opt IOleContainer** ppContainer) {
273   *ppContainer = nullptr;
274   return E_NOINTERFACE;
275 }
276 
ShowObject()277 HRESULT STDMETHODCALLTYPE WebBrowser::ShowObject() { return S_OK; }
278 
OnShowWindow(BOOL fShow)279 HRESULT STDMETHODCALLTYPE WebBrowser::OnShowWindow(BOOL fShow) { return S_OK; }
280 
RequestNewObjectLayout()281 HRESULT STDMETHODCALLTYPE WebBrowser::RequestNewObjectLayout() {
282   return E_NOTIMPL;
283 }
284 
285 //////////////////////////////////////////////////////////////////////////////
286 // IDropTarget
287 //////////////////////////////////////////////////////////////////////////////
288 // This is a stub implementation which blocks all dropping. The main reason we
289 // want to do that is prevent accidentally dropping something on the control
290 // and having it navigate, because there's no recovering from that except to
291 // restart the app, and also it would look ridiculous. There could also be
292 // security implications though, which we'd rather just avoid engaging with
293 // altogether if we can.
294 
295 HRESULT STDMETHODCALLTYPE
DragEnter(__RPC__in_opt IDataObject * pDataObj,DWORD grfKeyState,POINTL pt,__RPC__inout DWORD * pdwEffect)296 WebBrowser::DragEnter(__RPC__in_opt IDataObject* pDataObj, DWORD grfKeyState,
297                       POINTL pt, __RPC__inout DWORD* pdwEffect) {
298   *pdwEffect = DROPEFFECT_NONE;
299   return S_OK;
300 }
301 
DragOver(DWORD grfKeyState,POINTL pt,__RPC__inout DWORD * pdwEffect)302 HRESULT STDMETHODCALLTYPE WebBrowser::DragOver(DWORD grfKeyState, POINTL pt,
303                                                __RPC__inout DWORD* pdwEffect) {
304   *pdwEffect = DROPEFFECT_NONE;
305   return S_OK;
306 }
307 
DragLeave()308 HRESULT STDMETHODCALLTYPE WebBrowser::DragLeave() { return S_OK; }
309 
Drop(__RPC__in_opt IDataObject * pDataObj,DWORD grfKeyState,POINTL pt,__RPC__inout DWORD * pdwEffect)310 HRESULT STDMETHODCALLTYPE WebBrowser::Drop(__RPC__in_opt IDataObject* pDataObj,
311                                            DWORD grfKeyState, POINTL pt,
312                                            __RPC__inout DWORD* pdwEffect) {
313   *pdwEffect = DROPEFFECT_NONE;
314   return S_OK;
315 }
316 
317 //////////////////////////////////////////////////////////////////////////////
318 // IStorage
319 //////////////////////////////////////////////////////////////////////////////
320 // We don't need anything that IStorage does, but we have to pass some
321 // implementation of it to OleCreate, so we need to have a stub version.
322 
CreateStream(__RPC__in_string const OLECHAR * pwcsName,DWORD grfMode,DWORD reserved1,DWORD reserved2,__RPC__deref_out_opt IStream ** ppstm)323 HRESULT STDMETHODCALLTYPE WebBrowser::CreateStream(
324     __RPC__in_string const OLECHAR* pwcsName, DWORD grfMode, DWORD reserved1,
325     DWORD reserved2, __RPC__deref_out_opt IStream** ppstm) {
326   *ppstm = nullptr;
327   return E_NOTIMPL;
328 }
329 
OpenStream(const OLECHAR * pwcsName,void * reserved1,DWORD grfMode,DWORD reserved2,IStream ** ppstm)330 HRESULT STDMETHODCALLTYPE WebBrowser::OpenStream(const OLECHAR* pwcsName,
331                                                  void* reserved1, DWORD grfMode,
332                                                  DWORD reserved2,
333                                                  IStream** ppstm) {
334   *ppstm = nullptr;
335   return E_NOTIMPL;
336 }
337 
CreateStorage(__RPC__in_string const OLECHAR * pwcsName,DWORD grfMode,DWORD reserved1,DWORD reserved2,__RPC__deref_out_opt IStorage ** ppstg)338 HRESULT STDMETHODCALLTYPE WebBrowser::CreateStorage(
339     __RPC__in_string const OLECHAR* pwcsName, DWORD grfMode, DWORD reserved1,
340     DWORD reserved2, __RPC__deref_out_opt IStorage** ppstg) {
341   *ppstg = nullptr;
342   return E_NOTIMPL;
343 }
344 
345 HRESULT STDMETHODCALLTYPE
OpenStorage(__RPC__in_opt_string const OLECHAR * pwcsName,__RPC__in_opt IStorage * pstgPriority,DWORD grfMode,__RPC__deref_opt_in_opt SNB snbExclude,DWORD reserved,__RPC__deref_out_opt IStorage ** ppstg)346 WebBrowser::OpenStorage(__RPC__in_opt_string const OLECHAR* pwcsName,
347                         __RPC__in_opt IStorage* pstgPriority, DWORD grfMode,
348                         __RPC__deref_opt_in_opt SNB snbExclude, DWORD reserved,
349                         __RPC__deref_out_opt IStorage** ppstg) {
350   return E_NOTIMPL;
351 }
352 
CopyTo(DWORD ciidExclude,const IID * rgiidExclude,__RPC__in_opt SNB snbExclude,IStorage * pstgDest)353 HRESULT STDMETHODCALLTYPE WebBrowser::CopyTo(DWORD ciidExclude,
354                                              const IID* rgiidExclude,
355                                              __RPC__in_opt SNB snbExclude,
356                                              IStorage* pstgDest) {
357   return E_NOTIMPL;
358 }
359 
MoveElementTo(__RPC__in_string const OLECHAR * pwcsName,__RPC__in_opt IStorage * pstgDest,__RPC__in_string const OLECHAR * pwcsNewName,DWORD grfFlags)360 HRESULT STDMETHODCALLTYPE WebBrowser::MoveElementTo(
361     __RPC__in_string const OLECHAR* pwcsName, __RPC__in_opt IStorage* pstgDest,
362     __RPC__in_string const OLECHAR* pwcsNewName, DWORD grfFlags) {
363   return E_NOTIMPL;
364 }
365 
Commit(DWORD grfCommitFlags)366 HRESULT STDMETHODCALLTYPE WebBrowser::Commit(DWORD grfCommitFlags) {
367   return E_NOTIMPL;
368 }
369 
Revert()370 HRESULT STDMETHODCALLTYPE WebBrowser::Revert() { return E_NOTIMPL; }
371 
EnumElements(DWORD reserved1,void * reserved2,DWORD reserved3,IEnumSTATSTG ** ppenum)372 HRESULT STDMETHODCALLTYPE WebBrowser::EnumElements(DWORD reserved1,
373                                                    void* reserved2,
374                                                    DWORD reserved3,
375                                                    IEnumSTATSTG** ppenum) {
376   return E_NOTIMPL;
377 }
378 
379 HRESULT STDMETHODCALLTYPE
DestroyElement(__RPC__in_string const OLECHAR * pwcsName)380 WebBrowser::DestroyElement(__RPC__in_string const OLECHAR* pwcsName) {
381   return E_NOTIMPL;
382 }
383 
384 HRESULT STDMETHODCALLTYPE
RenameElement(__RPC__in_string const OLECHAR * pwcsOldName,__RPC__in_string const OLECHAR * pwcsNewName)385 WebBrowser::RenameElement(__RPC__in_string const OLECHAR* pwcsOldName,
386                           __RPC__in_string const OLECHAR* pwcsNewName) {
387   return E_NOTIMPL;
388 }
389 
SetElementTimes(__RPC__in_opt_string const OLECHAR * pwcsName,__RPC__in_opt const FILETIME * pctime,__RPC__in_opt const FILETIME * patime,__RPC__in_opt const FILETIME * pmtime)390 HRESULT STDMETHODCALLTYPE WebBrowser::SetElementTimes(
391     __RPC__in_opt_string const OLECHAR* pwcsName,
392     __RPC__in_opt const FILETIME* pctime, __RPC__in_opt const FILETIME* patime,
393     __RPC__in_opt const FILETIME* pmtime) {
394   return E_NOTIMPL;
395 }
396 
SetClass(__RPC__in REFCLSID clsid)397 HRESULT STDMETHODCALLTYPE WebBrowser::SetClass(__RPC__in REFCLSID clsid) {
398   return S_OK;
399 }
400 
SetStateBits(DWORD grfStateBits,DWORD grfMask)401 HRESULT STDMETHODCALLTYPE WebBrowser::SetStateBits(DWORD grfStateBits,
402                                                    DWORD grfMask) {
403   return E_NOTIMPL;
404 }
405 
Stat(__RPC__out STATSTG * pstatstg,DWORD grfStatFlag)406 HRESULT STDMETHODCALLTYPE WebBrowser::Stat(__RPC__out STATSTG* pstatstg,
407                                            DWORD grfStatFlag) {
408   return E_NOTIMPL;
409 }
410 
411 //////////////////////////////////////////////////////////////////////////////
412 // IDocHostUIHandler
413 //////////////////////////////////////////////////////////////////////////////
414 // Our implementation for this interface is basically all about disabling
415 // things that we don't want/need.
416 
ShowContextMenu(DWORD dwID,POINT * ppt,IUnknown * pcmdtReserved,IDispatch * pdispReserved)417 HRESULT __stdcall WebBrowser::ShowContextMenu(DWORD dwID, POINT* ppt,
418                                               IUnknown* pcmdtReserved,
419                                               IDispatch* pdispReserved) {
420   // Returning S_OK signals that we've handled the request for a context menu
421   // (which we did, by doing nothing), so the control won't try to open one.
422   return S_OK;
423 }
424 
GetHostInfo(DOCHOSTUIINFO * pInfo)425 HRESULT __stdcall WebBrowser::GetHostInfo(DOCHOSTUIINFO* pInfo) {
426   pInfo->cbSize = sizeof(DOCHOSTUIINFO);
427   pInfo->dwFlags =
428       DOCHOSTUIFLAG_DIALOG | DOCHOSTUIFLAG_DISABLE_HELP_MENU |
429       DOCHOSTUIFLAG_NO3DBORDER | DOCHOSTUIFLAG_SCROLL_NO |
430       DOCHOSTUIFLAG_OPENNEWWIN | DOCHOSTUIFLAG_OVERRIDEBEHAVIORFACTORY |
431       DOCHOSTUIFLAG_THEME | DOCHOSTUIFLAG_LOCAL_MACHINE_ACCESS_CHECK |
432       DOCHOSTUIFLAG_DISABLE_UNTRUSTEDPROTOCOL | DOCHOSTUIFLAG_DPI_AWARE;
433   pInfo->dwDoubleClick = DOCHOSTUIDBLCLK_DEFAULT;
434   pInfo->pchHostCss = nullptr;
435   pInfo->pchHostNS = nullptr;
436   return S_OK;
437 }
438 
ShowUI(DWORD dwID,IOleInPlaceActiveObject * pActiveObject,IOleCommandTarget * pCommandTarget,IOleInPlaceFrame * pFrame,IOleInPlaceUIWindow * pDoc)439 HRESULT __stdcall WebBrowser::ShowUI(DWORD dwID,
440                                      IOleInPlaceActiveObject* pActiveObject,
441                                      IOleCommandTarget* pCommandTarget,
442                                      IOleInPlaceFrame* pFrame,
443                                      IOleInPlaceUIWindow* pDoc) {
444   return E_NOTIMPL;
445 }
446 
HideUI()447 HRESULT __stdcall WebBrowser::HideUI() { return E_NOTIMPL; }
448 
UpdateUI()449 HRESULT __stdcall WebBrowser::UpdateUI() { return E_NOTIMPL; }
450 
EnableModeless(BOOL fEnable)451 HRESULT __stdcall WebBrowser::EnableModeless(BOOL fEnable) { return E_NOTIMPL; }
452 
OnDocWindowActivate(BOOL fActivate)453 HRESULT __stdcall WebBrowser::OnDocWindowActivate(BOOL fActivate) {
454   return E_NOTIMPL;
455 }
456 
OnFrameWindowActivate(BOOL fActivate)457 HRESULT __stdcall WebBrowser::OnFrameWindowActivate(BOOL fActivate) {
458   return E_NOTIMPL;
459 }
460 
ResizeBorder(LPCRECT prcBorder,IOleInPlaceUIWindow * pUIWindow,BOOL fRameWindow)461 HRESULT __stdcall WebBrowser::ResizeBorder(LPCRECT prcBorder,
462                                            IOleInPlaceUIWindow* pUIWindow,
463                                            BOOL fRameWindow) {
464   return E_NOTIMPL;
465 }
466 
TranslateAccelerator(LPMSG lpMsg,const GUID * pguidCmdGroup,DWORD nCmdID)467 HRESULT __stdcall WebBrowser::TranslateAccelerator(LPMSG lpMsg,
468                                                    const GUID* pguidCmdGroup,
469                                                    DWORD nCmdID) {
470   return S_FALSE;
471 }
472 
GetOptionKeyPath(LPOLESTR * pchKey,DWORD dw)473 HRESULT __stdcall WebBrowser::GetOptionKeyPath(LPOLESTR* pchKey, DWORD dw) {
474   return E_NOTIMPL;
475 }
476 
GetDropTarget(IDropTarget * pDropTarget,IDropTarget ** ppDropTarget)477 HRESULT __stdcall WebBrowser::GetDropTarget(IDropTarget* pDropTarget,
478                                             IDropTarget** ppDropTarget) {
479   // The IDropTarget implementation that we need is an empty stub, so we'll do
480   // the easy and convenient thing and just use this object.
481   return QueryInterface(IID_PPV_ARGS(ppDropTarget));
482 }
483 
GetExternal(IDispatch ** ppDispatch)484 HRESULT __stdcall WebBrowser::GetExternal(IDispatch** ppDispatch) {
485   // This object has to implement IDispatch anyway so that we can use
486   // DISPID_AMBIENT_DLCONTROL, so we'll make this the external handler also.
487   return QueryInterface(IID_PPV_ARGS(ppDispatch));
488 }
489 
TranslateUrl(DWORD dwTranslate,LPWSTR pchURLIn,LPWSTR * ppchURLOut)490 HRESULT __stdcall WebBrowser::TranslateUrl(DWORD dwTranslate, LPWSTR pchURLIn,
491                                            LPWSTR* ppchURLOut) {
492   *ppchURLOut = nullptr;
493   return E_NOTIMPL;
494 }
495 
FilterDataObject(IDataObject * pDO,IDataObject ** ppDORet)496 HRESULT __stdcall WebBrowser::FilterDataObject(IDataObject* pDO,
497                                                IDataObject** ppDORet) {
498   *ppDORet = nullptr;
499   return E_NOTIMPL;
500 }
501 
502 //////////////////////////////////////////////////////////////////////////////
503 // IDocHostShowUI
504 //////////////////////////////////////////////////////////////////////////////
505 
ShowMessage(HWND hwnd,LPOLESTR lpstrText,LPOLESTR lpstrCaption,DWORD dwType,LPOLESTR lpstrHelpFile,DWORD dwHelpContext,LRESULT * plResult)506 HRESULT __stdcall WebBrowser::ShowMessage(HWND hwnd, LPOLESTR lpstrText,
507                                           LPOLESTR lpstrCaption, DWORD dwType,
508                                           LPOLESTR lpstrHelpFile,
509                                           DWORD dwHelpContext,
510                                           LRESULT* plResult) {
511   // Don't allow MSHTML to generate message boxes.
512   return S_OK;
513 }
514 
ShowHelp(HWND hwnd,LPOLESTR pszHelpFile,UINT uCommand,DWORD dwData,POINT ptMouse,IDispatch * pDispatchObjectHit)515 HRESULT __stdcall WebBrowser::ShowHelp(HWND hwnd, LPOLESTR pszHelpFile,
516                                        UINT uCommand, DWORD dwData,
517                                        POINT ptMouse,
518                                        IDispatch* pDispatchObjectHit) {
519   // Don't allow MSHTML to show any help.
520   return S_OK;
521 }
522 
523 //////////////////////////////////////////////////////////////////////////////
524 // IDispatch
525 //////////////////////////////////////////////////////////////////////////////
526 
527 // We're not using a type library.
GetTypeInfoCount(UINT * pctinfo)528 HRESULT __stdcall WebBrowser::GetTypeInfoCount(UINT* pctinfo) {
529   if (pctinfo) {
530     *pctinfo = 0;
531   }
532   return S_OK;
533 }
534 
GetTypeInfo(UINT iTInfo,LCID lcid,ITypeInfo ** ppTInfo)535 HRESULT __stdcall WebBrowser::GetTypeInfo(UINT iTInfo, LCID lcid,
536                                           ITypeInfo** ppTInfo) {
537   return E_NOTIMPL;
538 }
539 
GetIDsOfNames(REFIID riid,LPOLESTR * rgszNames,UINT cNames,LCID lcid,DISPID * rgDispId)540 HRESULT __stdcall WebBrowser::GetIDsOfNames(REFIID riid, LPOLESTR* rgszNames,
541                                             UINT cNames, LCID lcid,
542                                             DISPID* rgDispId) {
543   if (cNames != 1) {
544     return E_NOTIMPL;
545   }
546 
547   for (size_t i = 0; i < mCustomFunctions.size(); ++i) {
548     if (mCustomFunctions[i].mName == rgszNames[0]) {
549       // DISPID values need to be 1-indexed because 0 is reserved
550       // (DISPID_VALUE).
551       *rgDispId = i + 1;
552       return S_OK;
553     }
554   }
555 
556   *rgDispId = DISPID_UNKNOWN;
557   return DISP_E_UNKNOWNNAME;
558 }
559 
Invoke(DISPID dispIdMember,REFIID riid,LCID lcid,WORD wFlags,DISPPARAMS * pDispParams,VARIANT * pVarResult,EXCEPINFO * pExcepInfo,UINT * puArgErr)560 HRESULT __stdcall WebBrowser::Invoke(DISPID dispIdMember, REFIID riid,
561                                      LCID lcid, WORD wFlags,
562                                      DISPPARAMS* pDispParams,
563                                      VARIANT* pVarResult, EXCEPINFO* pExcepInfo,
564                                      UINT* puArgErr) {
565   if (dispIdMember == DISPID_AMBIENT_DLCONTROL && pVarResult) {
566     VariantClear(pVarResult);
567     pVarResult->vt = VT_I4;
568     // As a light security measure, disable a bunch of stuff we don't want
569     // to be able to run in the web control.
570     pVarResult->intVal = DLCTL_NO_JAVA | DLCTL_NO_DLACTIVEXCTLS |
571                          DLCTL_NO_RUNACTIVEXCTLS | DLCTL_NO_FRAMEDOWNLOAD |
572                          DLCTL_NO_BEHAVIORS | DLCTL_NO_CLIENTPULL |
573                          DLCTL_NOFRAMES | DLCTL_FORCEOFFLINE | DLCTL_SILENT |
574                          DLCTL_OFFLINE | DLCTL_DLIMAGES;
575     return S_OK;
576   }
577 
578   // Otherwise this should be one of our custom functions.
579   // We only support invoking these as methods, not property access.
580   if ((wFlags & DISPATCH_METHOD) == 0) {
581     return DISP_E_TYPEMISMATCH;
582   }
583 
584   // Make sure this DISPID is valid in our custom functions list.
585   // DISPID values are 1-indexed because 0 is reserved (DISPID_VALUE).
586   DISPID customFunctionIndex = dispIdMember - 1;
587   if (customFunctionIndex < 0 ||
588       customFunctionIndex >= (DISPID)mCustomFunctions.size()) {
589     return DISP_E_MEMBERNOTFOUND;
590   }
591 
592   // If the caller passed an argument to this custom function, use it.
593   // If not, make an empty VARIANT we can pass to it instead.
594   VARIANT argument;
595   VariantInit(&argument);
596   if (pDispParams->cArgs > 0) {
597     argument = pDispParams->rgvarg[0];
598   }
599 
600   CustomFunctionRecord foundFunction = mCustomFunctions[customFunctionIndex];
601   foundFunction.mFunction(foundFunction.mArg, argument, pVarResult);
602 
603   return S_OK;
604 }
605