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 }