tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

WebBrowser.cpp (20704B)


      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 
      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 
     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 
     60 void WebBrowser::Shutdown() {
     61  if (mOleObject) {
     62    mOleObject->Close(OLECLOSE_NOSAVE);
     63    mOleObject->SetClientSite(nullptr);
     64  }
     65 }
     66 
     67 bool WebBrowser::IsInitialized() { return mOleObject != nullptr; }
     68 
     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 
     85 void WebBrowser::SetRect(const RECT& _rc) {
     86  mRect = _rc;
     87 
     88  if (mOleInPlaceObject) {
     89    mOleInPlaceObject->SetObjectRects(&mRect, &mRect);
     90  }
     91 }
     92 
     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 
    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 
    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 
    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 
    157 ULONG STDMETHODCALLTYPE WebBrowser::AddRef() {
    158  return InterlockedIncrement(&mComRefCount);
    159 }
    160 
    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
    174 WebBrowser::GetWindow(__RPC__deref_out_opt HWND* phwnd) {
    175  *phwnd = mHwndParent;
    176  return S_OK;
    177 }
    178 
    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 
    188 HRESULT STDMETHODCALLTYPE WebBrowser::CanInPlaceActivate() {
    189  // We always support in-place activation.
    190  return S_OK;
    191 }
    192 
    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 
    202 HRESULT STDMETHODCALLTYPE WebBrowser::OnUIActivate() {
    203  // Nothing to do before activating the control's UI.
    204  return S_OK;
    205 }
    206 
    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 
    225 HRESULT STDMETHODCALLTYPE WebBrowser::Scroll(SIZE scrollExtant) {
    226  // We should have disabled all scrollbars.
    227  return E_NOTIMPL;
    228 }
    229 
    230 HRESULT STDMETHODCALLTYPE WebBrowser::OnUIDeactivate(BOOL fUndoable) {
    231  // Nothing to do after deactivating the control's UI.
    232  return S_OK;
    233 }
    234 
    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.
    245 HRESULT STDMETHODCALLTYPE WebBrowser::DiscardUndoState() { return E_NOTIMPL; }
    246 
    247 HRESULT STDMETHODCALLTYPE WebBrowser::DeactivateAndUndo() { return E_NOTIMPL; }
    248 
    249 // We don't support moving or resizing the control.
    250 HRESULT STDMETHODCALLTYPE
    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 
    263 HRESULT STDMETHODCALLTYPE WebBrowser::SaveObject() { return E_NOTIMPL; }
    264 
    265 HRESULT STDMETHODCALLTYPE
    266 WebBrowser::GetMoniker(DWORD dwAssign, DWORD dwWhichMoniker,
    267                       __RPC__deref_out_opt IMoniker** ppmk) {
    268  return E_NOTIMPL;
    269 }
    270 
    271 HRESULT STDMETHODCALLTYPE
    272 WebBrowser::GetContainer(__RPC__deref_out_opt IOleContainer** ppContainer) {
    273  *ppContainer = nullptr;
    274  return E_NOINTERFACE;
    275 }
    276 
    277 HRESULT STDMETHODCALLTYPE WebBrowser::ShowObject() { return S_OK; }
    278 
    279 HRESULT STDMETHODCALLTYPE WebBrowser::OnShowWindow(BOOL fShow) { return S_OK; }
    280 
    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
    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 
    302 HRESULT STDMETHODCALLTYPE WebBrowser::DragOver(DWORD grfKeyState, POINTL pt,
    303                                               __RPC__inout DWORD* pdwEffect) {
    304  *pdwEffect = DROPEFFECT_NONE;
    305  return S_OK;
    306 }
    307 
    308 HRESULT STDMETHODCALLTYPE WebBrowser::DragLeave() { return S_OK; }
    309 
    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 
    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 
    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 
    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
    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 
    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 
    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 
    366 HRESULT STDMETHODCALLTYPE WebBrowser::Commit(DWORD grfCommitFlags) {
    367  return E_NOTIMPL;
    368 }
    369 
    370 HRESULT STDMETHODCALLTYPE WebBrowser::Revert() { return E_NOTIMPL; }
    371 
    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
    380 WebBrowser::DestroyElement(__RPC__in_string const OLECHAR* pwcsName) {
    381  return E_NOTIMPL;
    382 }
    383 
    384 HRESULT STDMETHODCALLTYPE
    385 WebBrowser::RenameElement(__RPC__in_string const OLECHAR* pwcsOldName,
    386                          __RPC__in_string const OLECHAR* pwcsNewName) {
    387  return E_NOTIMPL;
    388 }
    389 
    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 
    397 HRESULT STDMETHODCALLTYPE WebBrowser::SetClass(__RPC__in REFCLSID clsid) {
    398  return S_OK;
    399 }
    400 
    401 HRESULT STDMETHODCALLTYPE WebBrowser::SetStateBits(DWORD grfStateBits,
    402                                                   DWORD grfMask) {
    403  return E_NOTIMPL;
    404 }
    405 
    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 
    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 
    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 
    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 
    447 HRESULT __stdcall WebBrowser::HideUI() { return E_NOTIMPL; }
    448 
    449 HRESULT __stdcall WebBrowser::UpdateUI() { return E_NOTIMPL; }
    450 
    451 HRESULT __stdcall WebBrowser::EnableModeless(BOOL fEnable) { return E_NOTIMPL; }
    452 
    453 HRESULT __stdcall WebBrowser::OnDocWindowActivate(BOOL fActivate) {
    454  return E_NOTIMPL;
    455 }
    456 
    457 HRESULT __stdcall WebBrowser::OnFrameWindowActivate(BOOL fActivate) {
    458  return E_NOTIMPL;
    459 }
    460 
    461 HRESULT __stdcall WebBrowser::ResizeBorder(LPCRECT prcBorder,
    462                                           IOleInPlaceUIWindow* pUIWindow,
    463                                           BOOL fRameWindow) {
    464  return E_NOTIMPL;
    465 }
    466 
    467 HRESULT __stdcall WebBrowser::TranslateAccelerator(LPMSG lpMsg,
    468                                                   const GUID* pguidCmdGroup,
    469                                                   DWORD nCmdID) {
    470  return S_FALSE;
    471 }
    472 
    473 HRESULT __stdcall WebBrowser::GetOptionKeyPath(LPOLESTR* pchKey, DWORD dw) {
    474  return E_NOTIMPL;
    475 }
    476 
    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 
    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 
    490 HRESULT __stdcall WebBrowser::TranslateUrl(DWORD dwTranslate, LPWSTR pchURLIn,
    491                                           LPWSTR* ppchURLOut) {
    492  *ppchURLOut = nullptr;
    493  return E_NOTIMPL;
    494 }
    495 
    496 HRESULT __stdcall WebBrowser::FilterDataObject(IDataObject* pDO,
    497                                               IDataObject** ppDORet) {
    498  *ppDORet = nullptr;
    499  return E_NOTIMPL;
    500 }
    501 
    502 //////////////////////////////////////////////////////////////////////////////
    503 // IDocHostShowUI
    504 //////////////////////////////////////////////////////////////////////////////
    505 
    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 
    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.
    528 HRESULT __stdcall WebBrowser::GetTypeInfoCount(UINT* pctinfo) {
    529  if (pctinfo) {
    530    *pctinfo = 0;
    531  }
    532  return S_OK;
    533 }
    534 
    535 HRESULT __stdcall WebBrowser::GetTypeInfo(UINT iTInfo, LCID lcid,
    536                                          ITypeInfo** ppTInfo) {
    537  return E_NOTIMPL;
    538 }
    539 
    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 
    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 }