// Copyright © 2010 The CefSharp Authors. All rights reserved. // // Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. #include "Stdafx.h" #include "ClientAdapter.h" #include "include\cef_client.h" #include "include\wrapper\cef_stream_resource_handler.h" #include "CefAuthCallbackWrapper.h" #include "CefBeforeDownloadCallbackWrapper.h" #include "CefCertificateCallbackWrapper.h" #include "CefContextMenuParamsWrapper.h" #include "CefDownloadItemCallbackWrapper.h" #include "DragData.h" #include "CefFileDialogCallbackWrapper.h" #include "CefFrameWrapper.h" #include "CefJSDialogCallbackWrapper.h" #include "CefMenuModelWrapper.h" #include "Request.h" #include "CefResourceRequestHandlerAdapter.h" #include "CefRequestCallbackWrapper.h" #include "CefRunContextMenuCallbackWrapper.h" #include "CefPermissionPromptCallbackWrapper.h" #include "CefSslInfoWrapper.h" #include "CefBrowserWrapper.h" #include "CefMediaAccessCallbackWrapper.h" #include "ManagedCefBrowserAdapter.h" #include "Messaging\Messages.h" #include "PopupFeatures.h" #include "Serialization\Primitives.h" #include "Serialization\V8Serialization.h" #include "Serialization\JsObjectsSerialization.h" #include "Serialization\ObjectsSerialization.h" #include "TypeConversion.h" #include "WindowInfo.h" using namespace CefSharp::Internals::Messaging; using namespace CefSharp::Internals::Serialization; using namespace System::Security::Cryptography::X509Certificates; namespace CefSharp { namespace Internals { IBrowser^ ClientAdapter::GetBrowserWrapper(int browserId) { if (_cefBrowser.get()) { if (_cefBrowser->GetIdentifier() == browserId) { return _browser; } //IJavascriptCallbacks that are finalized after the browser has been Disposed //but before the IBrowserAdapter.IsDisposed is set might end up here //attempting to access _popupBrowsers which has been set to null already. auto popupBrowsers = _popupBrowsers; if (Object::ReferenceEquals(popupBrowsers, nullptr)) { return nullptr; } IBrowser^ popupBrowser; if (popupBrowsers->TryGetValue(browserId, popupBrowser)) { return popupBrowser; } } return nullptr; } IBrowser^ ClientAdapter::GetBrowserWrapper(int browserId, bool isPopup) { if (!isPopup) { return _browser; } IBrowser^ popupBrowser; if (_popupBrowsers->TryGetValue(browserId, popupBrowser)) { return popupBrowser; } // For popups that were hosted using a ChromiumWebBrowser instance if (_browserControl->HasParent) { return _browser; } return nullptr; } // Is a main browser if isPopuo == false or the IBrowser instance is directly associated // with the ChromiumWebBrowser instance. Should be true in cases // where ChromiumWebBrowser is instanciated directly or // when a popup is hosted in a ChromiumWebBrowser instance // For popups hosted in ChromiumWebBrowser instances it's important // that DevTools popups return false; bool ClientAdapter::IsMainBrowser(bool isPopup, int browserId) { // Main browser is always true if (!isPopup) { return true; } // If popup and HasParent == false then always false if (!_browserControl->HasParent) { return false; } // This method is called from OnAfterCreated before _cefBrowser is set // If the _cefBrowser reference is null then this should be a ChromiumWebBrowser // hosted as a popup if (!_cefBrowser.get()) { return true; } // For popups hosted in ChromiumWebBrowser instance directly (non DevTools popup) // then return true; if (_cefBrowser->GetIdentifier() == browserId) { return true; } return false; } void ClientAdapter::CloseAllPopups(bool forceClose) { if (_popupBrowsers->Count > 0) { for each (IBrowser^ browser in _popupBrowsers->Values) { browser->GetHost()->CloseBrowser(forceClose); // NOTE: We don't dispose the IBrowsers here // because ->CloseBrowser() will invoke // ->OnBeforeClose() for the browser. // OnBeforeClose() disposes the IBrowser there. } } } bool ClientAdapter::OnBeforePopup(CefRefPtr browser, CefRefPtr frame, const CefString& target_url, const CefString& target_frame_name, CefLifeSpanHandler::WindowOpenDisposition target_disposition, bool user_gesture, const CefPopupFeatures& popupFeatures, CefWindowInfo& windowInfo, CefRefPtr& client, CefBrowserSettings& settings, CefRefPtr& extraInfo, bool* no_javascript_access) { auto handler = _browserControl->LifeSpanHandler; if (handler == nullptr) { return false; } IWebBrowser^ newBrowser = nullptr; bool createdWrapper = false; auto browserWrapper = GetBrowserWrapper(browser->GetIdentifier(), browser->IsPopup()); CefFrameWrapper frameWrapper(frame); PopupFeatures popupFeaturesWrapper(&popupFeatures); BrowserSettings browserSettingsWrapper(&settings); WindowInfo windowInfoWrapper(&windowInfo); auto result = handler->OnBeforePopup( _browserControl, browserWrapper, %frameWrapper, StringUtils::ToClr(target_url), StringUtils::ToClr(target_frame_name), (CefSharp::WindowOpenDisposition)target_disposition, user_gesture, %popupFeaturesWrapper, %windowInfoWrapper, %browserSettingsWrapper, *no_javascript_access, newBrowser); if (newBrowser != nullptr) { //newBrowser should never be set to _browserControl (I've seen user code where someone attepted to do this). //So throw exception to make that perfectly clear. if (Object::ReferenceEquals(_browserControl, newBrowser)) { throw gcnew Exception("newBrowser should be a new instance of ChromiumWebBrowser or null."); } //newBrowser is not null and result is true, whilst the documentation clearly states returning true will //cancel popup creation people keep expecting that newBrowser will do something which it won't if (result == true) { throw gcnew Exception("returning true cancels popup creation, if you return true newBrowser should be set to null." + "Previously no exception was thrown in this instance, this exception has been added to reduce the number of" + " support requests from people returning true and setting newBrowser and expecting popups to work."); } auto newBrowserInternal = dynamic_cast(newBrowser); if (newBrowserInternal != nullptr) { //This should already be set using the SetAsPopup extension, just making doubly sure newBrowserInternal->HasParent = true; auto browserAdapter = dynamic_cast(newBrowserInternal->BrowserAdapter); if (browserAdapter != nullptr) { client = browserAdapter->GetClientAdapter().get(); } } } return result; } void ClientAdapter::OnAfterCreated(CefRefPtr browser) { BrowserRefCounter::Instance->Increment(_browserControl->GetType()); auto browserWrapper = gcnew CefBrowserWrapper(browser); if (IsMainBrowser(browser->IsPopup(), browser->GetIdentifier())) { _browserHwnd = browser->GetHost()->GetWindowHandle(); _cefBrowser = browser; _browser = browserWrapper; if (!Object::ReferenceEquals(_browserAdapter, nullptr)) { _browserAdapter->OnAfterBrowserCreated(browserWrapper); } } else { // Add to the list of popup browsers. _popupBrowsers->Add(browser->GetIdentifier(), browserWrapper); } auto handler = _browserControl->LifeSpanHandler; if (handler != nullptr) { handler->OnAfterCreated(_browserControl, browserWrapper); } } bool ClientAdapter::DoClose(CefRefPtr browser) { auto handler = _browserControl->LifeSpanHandler; if (handler != nullptr) { //By this point it's possible IBrowser references have been disposed //Rather than attempting to rework the rather complex closing logic //It's easier to pass in a new wrapper and dispose it straight away CefBrowserWrapper browserWrapper(browser); return handler->DoClose(_browserControl, %browserWrapper); } return false; } void ClientAdapter::OnBeforeClose(CefRefPtr browser) { auto handler = _browserControl->LifeSpanHandler; if (handler != nullptr) { //By this point it's possible IBrowser references have been disposed //Rather than attempting to rework the rather complex closing logic //It's easier to pass in a new wrapper and dispose it straight away CefBrowserWrapper browserWrapper(browser); handler->OnBeforeClose(_browserControl, %browserWrapper); } if (IsMainBrowser(browser->IsPopup(), browser->GetIdentifier())) { _cefBrowser = nullptr; } else { // Remove from the browser popup list. auto browserWrapper = GetBrowserWrapper(browser->GetIdentifier(), true); _popupBrowsers->Remove(browser->GetIdentifier()); // Dispose the CefBrowserWrapper delete browserWrapper; } BrowserRefCounter::Instance->Decrement(_browserControl->GetType()); } void ClientAdapter::OnLoadingStateChange(CefRefPtr browser, bool isLoading, bool canGoBack, bool canGoForward) { auto browserWrapper = GetBrowserWrapper(browser->GetIdentifier(), browser->IsPopup()); auto args = gcnew LoadingStateChangedEventArgs(browserWrapper, canGoBack, canGoForward, isLoading); if (IsMainBrowser(browser->IsPopup(), browser->GetIdentifier())) { _browserControl->SetLoadingStateChange(args); } auto handler = _browserControl->LoadHandler; if (handler != nullptr) { handler->OnLoadingStateChange(_browserControl, args); } } void ClientAdapter::OnAddressChange(CefRefPtr browser, CefRefPtr frame, const CefString& address) { auto browserWrapper = GetBrowserWrapper(browser->GetIdentifier(), browser->IsPopup()); auto args = gcnew AddressChangedEventArgs(browserWrapper, StringUtils::ToClr(address)); if (IsMainBrowser(browser->IsPopup(), browser->GetIdentifier())) { _browserControl->SetAddress(args); } auto handler = _browserControl->DisplayHandler; if (handler != nullptr) { handler->OnAddressChanged(_browserControl, args); } } bool ClientAdapter::OnAutoResize(CefRefPtr browser, const CefSize& new_size) { auto handler = _browserControl->DisplayHandler; if (handler == nullptr) { return false; } auto browserWrapper = GetBrowserWrapper(browser->GetIdentifier(), browser->IsPopup()); return handler->OnAutoResize(_browserControl, browserWrapper, CefSharp::Structs::Size(new_size.width, new_size.height)); } bool ClientAdapter::OnCursorChange(CefRefPtr browser, CefCursorHandle cursor, cef_cursor_type_t type, const CefCursorInfo& custom_cursor_info) { auto handler = _browserControl->DisplayHandler; if (handler == nullptr) { InternalCursorChange(browser, cursor, type, custom_cursor_info); return false; } CursorInfo customCursorInfo; //TODO: this is duplicated in RenderClientAdapter::InternalCursorChange //Only create the struct when we actually have a custom cursor if (type == cef_cursor_type_t::CT_CUSTOM) { Point hotspot = Point(custom_cursor_info.hotspot.x, custom_cursor_info.hotspot.y); Size size = Size(custom_cursor_info.size.width, custom_cursor_info.size.height); customCursorInfo = CursorInfo(IntPtr((void*)custom_cursor_info.buffer), hotspot, custom_cursor_info.image_scale_factor, size); } auto browserWrapper = GetBrowserWrapper(browser->GetIdentifier(), browser->IsPopup()); auto handled = handler->OnCursorChange(_browserControl, browserWrapper, (IntPtr)cursor, (CefSharp::Enums::CursorType)type, customCursorInfo); if (handled) { return true; } InternalCursorChange(browser, cursor, type, custom_cursor_info); return false; }; void ClientAdapter::InternalCursorChange(CefRefPtr browser, CefCursorHandle cursor, cef_cursor_type_t type, const CefCursorInfo& custom_cursor_info) { } void ClientAdapter::OnTitleChange(CefRefPtr browser, const CefString& title) { auto browserWrapper = GetBrowserWrapper(browser->GetIdentifier(), browser->IsPopup()); auto args = gcnew TitleChangedEventArgs(browserWrapper, StringUtils::ToClr(title)); if (IsMainBrowser(browser->IsPopup(), browser->GetIdentifier())) { _browserControl->SetTitle(args); } else { // Set the popup window title auto hwnd = browser->GetHost()->GetWindowHandle(); SetWindowText(hwnd, std::wstring(title).c_str()); } auto handler = _browserControl->DisplayHandler; if (handler != nullptr) { handler->OnTitleChanged(_browserControl, args); } } void ClientAdapter::OnFaviconURLChange(CefRefPtr browser, const std::vector& iconUrls) { auto handler = _browserControl->DisplayHandler; if (handler != nullptr) { auto browserWrapper = GetBrowserWrapper(browser->GetIdentifier(), browser->IsPopup()); handler->OnFaviconUrlChange(_browserControl, browserWrapper, StringUtils::ToClr(iconUrls)); } } void ClientAdapter::OnFullscreenModeChange(CefRefPtr browser, bool fullscreen) { auto handler = _browserControl->DisplayHandler; if (handler != nullptr) { auto browserWrapper = GetBrowserWrapper(browser->GetIdentifier(), browser->IsPopup()); handler->OnFullscreenModeChange(_browserControl, browserWrapper, fullscreen); } } void ClientAdapter::OnLoadingProgressChange(CefRefPtr browser, double progress) { auto handler = _browserControl->DisplayHandler; if (handler != nullptr) { auto browserWrapper = GetBrowserWrapper(browser->GetIdentifier(), browser->IsPopup()); handler->OnLoadingProgressChange(_browserControl, browserWrapper, progress); } } bool ClientAdapter::OnTooltip(CefRefPtr browser, CefString& text) { auto tooltip = StringUtils::ToClr(text); bool hasChanged = tooltip != _tooltip; bool returnFlag = true; //NOTE: Only called if tooltip changed otherwise called many times // also only called when using OSR, https://github.com/chromiumembedded/cef/issues/783 if (hasChanged) { auto handler = _browserControl->DisplayHandler; if (handler != nullptr) { returnFlag = handler->OnTooltipChanged(_browserControl, tooltip); } if (IsMainBrowser(browser->IsPopup(), browser->GetIdentifier())) { _tooltip = tooltip; _browserControl->SetTooltipText(_tooltip); } } return returnFlag; } bool ClientAdapter::OnConsoleMessage(CefRefPtr browser, cef_log_severity_t level, const CefString& message, const CefString& source, int line) { auto browserWrapper = GetBrowserWrapper(browser->GetIdentifier(), browser->IsPopup()); auto args = gcnew ConsoleMessageEventArgs(browserWrapper, (LogSeverity)level, StringUtils::ToClr(message), StringUtils::ToClr(source), line); if (IsMainBrowser(browser->IsPopup(), browser->GetIdentifier())) { _browserControl->OnConsoleMessage(args); } auto handler = _browserControl->DisplayHandler; if (handler == nullptr) { return false; } return handler->OnConsoleMessage(_browserControl, args); } void ClientAdapter::OnStatusMessage(CefRefPtr browser, const CefString& value) { auto browserWrapper = GetBrowserWrapper(browser->GetIdentifier(), browser->IsPopup()); auto args = gcnew StatusMessageEventArgs(browserWrapper, StringUtils::ToClr(value)); if (IsMainBrowser(browser->IsPopup(), browser->GetIdentifier())) { _browserControl->OnStatusMessage(args); } auto handler = _browserControl->DisplayHandler; if (handler != nullptr) { handler->OnStatusMessage(_browserControl, args); } } bool ClientAdapter::OnKeyEvent(CefRefPtr browser, const CefKeyEvent& event, CefEventHandle os_event) { auto handler = _browserControl->KeyboardHandler; if (handler == nullptr) { return false; } auto browserWrapper = GetBrowserWrapper(browser->GetIdentifier(), browser->IsPopup()); return handler->OnKeyEvent( _browserControl, browserWrapper, (KeyType)event.type, event.windows_key_code, event.native_key_code, (CefEventFlags)event.modifiers, event.is_system_key == 1); } bool ClientAdapter::OnPreKeyEvent(CefRefPtr browser, const CefKeyEvent& event, CefEventHandle os_event, bool* is_keyboard_shortcut) { auto handler = _browserControl->KeyboardHandler; if (handler == nullptr) { return false; } auto browserWrapper = GetBrowserWrapper(browser->GetIdentifier(), browser->IsPopup()); return handler->OnPreKeyEvent( _browserControl, browserWrapper, (KeyType)event.type, event.windows_key_code, event.native_key_code, (CefEventFlags)event.modifiers, event.is_system_key == 1, *is_keyboard_shortcut); } void ClientAdapter::OnLoadStart(CefRefPtr browser, CefRefPtr frame, TransitionType transitionType) { auto browserWrapper = GetBrowserWrapper(browser->GetIdentifier(), browser->IsPopup()); CefFrameWrapper frameWrapper(frame); if (IsMainBrowser(browser->IsPopup(), browser->GetIdentifier())) { _browserControl->OnFrameLoadStart(gcnew FrameLoadStartEventArgs(browserWrapper, %frameWrapper, (CefSharp::TransitionType)transitionType)); } auto handler = _browserControl->LoadHandler; if (handler != nullptr) { handler->OnFrameLoadStart(_browserControl, gcnew FrameLoadStartEventArgs(browserWrapper, %frameWrapper, (CefSharp::TransitionType)transitionType)); } } void ClientAdapter::OnLoadEnd(CefRefPtr browser, CefRefPtr frame, int httpStatusCode) { auto browserWrapper = GetBrowserWrapper(browser->GetIdentifier(), browser->IsPopup()); CefFrameWrapper frameWrapper(frame); if (IsMainBrowser(browser->IsPopup(), browser->GetIdentifier())) { _browserControl->OnFrameLoadEnd(gcnew FrameLoadEndEventArgs(browserWrapper, %frameWrapper, httpStatusCode)); } auto handler = _browserControl->LoadHandler; if (handler != nullptr) { handler->OnFrameLoadEnd(_browserControl, gcnew FrameLoadEndEventArgs(browserWrapper, %frameWrapper, httpStatusCode)); } } void ClientAdapter::OnLoadError(CefRefPtr browser, CefRefPtr frame, ErrorCode errorCode, const CefString& errorText, const CefString& failedUrl) { auto browserWrapper = GetBrowserWrapper(browser->GetIdentifier(), browser->IsPopup()); CefFrameWrapper frameWrapper(frame); if (IsMainBrowser(browser->IsPopup(), browser->GetIdentifier())) { _browserControl->OnLoadError(gcnew LoadErrorEventArgs(browserWrapper, %frameWrapper, (CefErrorCode)errorCode, StringUtils::ToClr(errorText), StringUtils::ToClr(failedUrl))); } auto handler = _browserControl->LoadHandler; if (handler != nullptr) { handler->OnLoadError(_browserControl, gcnew LoadErrorEventArgs(browserWrapper, %frameWrapper, (CefErrorCode)errorCode, StringUtils::ToClr(errorText), StringUtils::ToClr(failedUrl))); } } bool ClientAdapter::OnBeforeBrowse(CefRefPtr browser, CefRefPtr frame, CefRefPtr request, bool userGesture, bool isRedirect) { auto handler = _browserControl->RequestHandler; if (handler == nullptr) { return false; } auto browserWrapper = GetBrowserWrapper(browser->GetIdentifier(), browser->IsPopup()); CefFrameWrapper frameWrapper(frame); Request requestWrapper(request); return handler->OnBeforeBrowse(_browserControl, browserWrapper, %frameWrapper, %requestWrapper, userGesture, isRedirect); } bool ClientAdapter::OnOpenURLFromTab(CefRefPtr browser, CefRefPtr frame, const CefString& targetUrl, CefRequestHandler::WindowOpenDisposition targetDisposition, bool userGesture) { auto handler = _browserControl->RequestHandler; if (handler == nullptr) { return false; } auto browserWrapper = GetBrowserWrapper(browser->GetIdentifier(), browser->IsPopup()); CefFrameWrapper frameWrapper(frame); return handler->OnOpenUrlFromTab(_browserControl, browserWrapper, %frameWrapper, StringUtils::ToClr(targetUrl), (CefSharp::WindowOpenDisposition)targetDisposition, userGesture); } CefRefPtr ClientAdapter::GetResourceRequestHandler(CefRefPtr browser, CefRefPtr frame, CefRefPtr request, bool isNavigation, bool isDownload, const CefString& requestInitiator, bool& disableDefaultHandling) { auto handler = _browserControl->RequestHandler; auto resourceRequestHandlerFactory = _browserControl->ResourceRequestHandlerFactory; //No handler and no factory, we'll just return null if (handler == nullptr && resourceRequestHandlerFactory == nullptr) { return nullptr; } auto browserWrapper = GetBrowserWrapper(browser->GetIdentifier(), browser->IsPopup()); CefFrameWrapper frameWrapper(frame); Request requestWrapper(request); if (handler != nullptr) { auto resourceRequestHandler = handler->GetResourceRequestHandler(_browserControl, browserWrapper, %frameWrapper, %requestWrapper, isNavigation, isDownload, StringUtils::ToClr(requestInitiator), disableDefaultHandling); if (resourceRequestHandler != nullptr) { return new CefResourceRequestHandlerAdapter(_browserControl, resourceRequestHandler); } } if (resourceRequestHandlerFactory != nullptr && resourceRequestHandlerFactory->HasHandlers) { auto factoryHandler = resourceRequestHandlerFactory->GetResourceRequestHandler(_browserControl, browserWrapper, %frameWrapper, %requestWrapper, isNavigation, isDownload, StringUtils::ToClr(requestInitiator), disableDefaultHandling); if (factoryHandler != nullptr) { return new CefResourceRequestHandlerAdapter(_browserControl, factoryHandler); } } return nullptr; } bool ClientAdapter::OnCertificateError(CefRefPtr browser, cef_errorcode_t cert_error, const CefString& request_url, CefRefPtr ssl_info, CefRefPtr callback) { auto handler = _browserControl->RequestHandler; if (handler == nullptr) { return false; } // If callback is empty the error cannot be recovered from and the request will be canceled automatically. // Still notify the user of the certificate error just don't provide a callback. auto requestCallback = callback == nullptr ? nullptr : gcnew CefRequestCallbackWrapper(callback); auto browserWrapper = GetBrowserWrapper(browser->GetIdentifier(), browser->IsPopup()); auto sslInfoWrapper = gcnew CefSslInfoWrapper(ssl_info); return handler->OnCertificateError(_browserControl, browserWrapper, (CefErrorCode)cert_error, StringUtils::ToClr(request_url), sslInfoWrapper, requestCallback); } void ClientAdapter::OnRenderViewReady(CefRefPtr browser) { auto handler = _browserControl->RequestHandler; if (handler != nullptr) { auto browserWrapper = GetBrowserWrapper(browser->GetIdentifier(), browser->IsPopup()); handler->OnRenderViewReady(_browserControl, browserWrapper); } } void ClientAdapter::OnRenderProcessTerminated(CefRefPtr browser, TerminationStatus status, int errorCode, const CefString& errorString) { auto handler = _browserControl->RequestHandler; if (handler != nullptr) { auto browserWrapper = GetBrowserWrapper(browser->GetIdentifier(), browser->IsPopup()); handler->OnRenderProcessTerminated(_browserControl, browserWrapper, (CefTerminationStatus)status, errorCode, StringUtils::ToClr(errorString)); } } void ClientAdapter::OnDocumentAvailableInMainFrame(CefRefPtr browser) { auto handler = _browserControl->RequestHandler; if (handler != nullptr) { auto browserWrapper = GetBrowserWrapper(browser->GetIdentifier(), browser->IsPopup()); handler->OnDocumentAvailableInMainFrame(_browserControl, browserWrapper); } } bool ClientAdapter::GetAuthCredentials(CefRefPtr browser, const CefString& originUrl, bool isProxy, const CefString& host, int port, const CefString& realm, const CefString& scheme, CefRefPtr callback) { if (isProxy && CefSharpSettings::Proxy != nullptr && CefSharpSettings::Proxy->IP == StringUtils::ToClr(host) && CefSharpSettings::Proxy->HasUsernameAndPassword()) { callback->Continue(StringUtils::ToNative(CefSharpSettings::Proxy->Username), StringUtils::ToNative(CefSharpSettings::Proxy->Password)); return true; } auto handler = _browserControl->RequestHandler; if (handler == nullptr) { return false; } auto browserWrapper = GetBrowserWrapper(browser->GetIdentifier(), browser->IsPopup()); auto callbackWrapper = gcnew CefAuthCallbackWrapper(callback); return handler->GetAuthCredentials( _browserControl, browserWrapper, StringUtils::ToClr(originUrl), isProxy, StringUtils::ToClr(host), port, StringUtils::ToClr(realm), StringUtils::ToClr(scheme), callbackWrapper); } bool ClientAdapter::OnSelectClientCertificate(CefRefPtr browser, bool isProxy, const CefString& host, int port, const CefRequestHandler::X509CertificateList& certificates, CefRefPtr callback) { auto handler = _browserControl->RequestHandler; if (handler == nullptr) { return false; } auto browserWrapper = GetBrowserWrapper(browser->GetIdentifier(), browser->IsPopup()); auto list = gcnew X509Certificate2Collection(); // Create a copy of the vector in an attempt to fix #2948 CefRequestHandler::X509CertificateList certs; std::vector >::const_iterator it = certificates.begin(); for (; it != certificates.end(); ++it) { auto bytes((*it)->GetDEREncoded()); auto byteSize = bytes->GetSize(); auto bufferByte = gcnew cli::array(byteSize); pin_ptr src = &bufferByte[0]; // pin pointer to first element in arr bytes->GetData(static_cast(src), byteSize, 0); auto cert = gcnew X509Certificate2(bufferByte); list->Add(cert); certs.push_back(*it); } auto callbackWrapper = gcnew CefCertificateCallbackWrapper(callback, certs); return handler->OnSelectClientCertificate( _browserControl, browserWrapper, isProxy, StringUtils::ToClr(host), port, list, callbackWrapper); } void ClientAdapter::OnBeforeContextMenu(CefRefPtr browser, CefRefPtr frame, CefRefPtr params, CefRefPtr model) { auto handler = _browserControl->MenuHandler; if (handler != nullptr) { auto browserWrapper = GetBrowserWrapper(browser->GetIdentifier(), browser->IsPopup()); CefFrameWrapper frameWrapper(frame); CefContextMenuParamsWrapper contextMenuParamsWrapper(params); CefMenuModelWrapper menuModelWrapper(model); handler->OnBeforeContextMenu(_browserControl, browserWrapper, %frameWrapper, %contextMenuParamsWrapper, %menuModelWrapper); } } bool ClientAdapter::OnContextMenuCommand(CefRefPtr browser, CefRefPtr frame, CefRefPtr params, int commandId, EventFlags eventFlags) { auto handler = _browserControl->MenuHandler; if (handler != nullptr) { auto browserWrapper = GetBrowserWrapper(browser->GetIdentifier(), browser->IsPopup()); CefFrameWrapper frameWrapper(frame); CefContextMenuParamsWrapper contextMenuParamsWrapper(params); return handler->OnContextMenuCommand(_browserControl, browserWrapper, %frameWrapper, %contextMenuParamsWrapper, (CefMenuCommand)commandId, (CefEventFlags)eventFlags); } return false; } void ClientAdapter::OnContextMenuDismissed(CefRefPtr browser, CefRefPtr frame) { auto handler = _browserControl->MenuHandler; if (handler != nullptr) { auto browserWrapper = GetBrowserWrapper(browser->GetIdentifier(), browser->IsPopup()); CefFrameWrapper frameWrapper(frame); handler->OnContextMenuDismissed(_browserControl, browserWrapper, %frameWrapper); } } bool ClientAdapter::RunContextMenu(CefRefPtr browser, CefRefPtr frame, CefRefPtr params, CefRefPtr model, CefRefPtr callback) { auto handler = _browserControl->MenuHandler; if (handler == nullptr) { return false; } auto browserWrapper = GetBrowserWrapper(browser->GetIdentifier(), browser->IsPopup()); CefFrameWrapper frameWrapper(frame); CefContextMenuParamsWrapper contextMenuParamsWrapper(params); CefMenuModelWrapper menuModelWrapper(model); auto callbackWrapper = gcnew CefRunContextMenuCallbackWrapper(callback); return handler->RunContextMenu(_browserControl, browserWrapper, %frameWrapper, %contextMenuParamsWrapper, %menuModelWrapper, callbackWrapper); } void ClientAdapter::OnGotFocus(CefRefPtr browser) { auto handler = _browserControl->FocusHandler; if (handler == nullptr) { return; } auto browserWrapper = GetBrowserWrapper(browser->GetIdentifier(), browser->IsPopup()); handler->OnGotFocus(_browserControl, browserWrapper); } bool ClientAdapter::OnSetFocus(CefRefPtr browser, FocusSource source) { auto handler = _browserControl->FocusHandler; if (handler == nullptr) { // Allow the focus to be set by default. return false; } //For DevTools (which is hosted as a popup) OnSetFocus is called before OnAfterCreated so we don't // have a reference to the standard popup IBrowser wrapper, so we just pass a // short term reference. CefBrowserWrapper browserWrapper(browser); return handler->OnSetFocus(_browserControl, %browserWrapper, (CefFocusSource)source); } void ClientAdapter::OnTakeFocus(CefRefPtr browser, bool next) { auto handler = _browserControl->FocusHandler; if (handler == nullptr) { return; } auto browserWrapper = GetBrowserWrapper(browser->GetIdentifier(), browser->IsPopup()); handler->OnTakeFocus(_browserControl, browserWrapper, next); } bool ClientAdapter::OnJSDialog(CefRefPtr browser, const CefString& origin_url, JSDialogType dialog_type, const CefString& message_text, const CefString& default_prompt_text, CefRefPtr callback, bool& suppress_message) { auto handler = _browserControl->JsDialogHandler; if (handler == nullptr) { return false; } auto browserWrapper = GetBrowserWrapper(browser->GetIdentifier(), browser->IsPopup()); auto callbackWrapper = gcnew CefJSDialogCallbackWrapper(callback); return handler->OnJSDialog(_browserControl, browserWrapper, StringUtils::ToClr(origin_url), (CefJsDialogType)dialog_type, StringUtils::ToClr(message_text), StringUtils::ToClr(default_prompt_text), callbackWrapper, suppress_message); } bool ClientAdapter::OnBeforeUnloadDialog(CefRefPtr browser, const CefString& message_text, bool is_reload, CefRefPtr callback) { auto handler = _browserControl->JsDialogHandler; if (handler == nullptr) { return false; } auto browserWrapper = GetBrowserWrapper(browser->GetIdentifier(), browser->IsPopup()); auto callbackWrapper = gcnew CefJSDialogCallbackWrapper(callback); return handler->OnBeforeUnloadDialog(_browserControl, browserWrapper, StringUtils::ToClr(message_text), is_reload, callbackWrapper); } void ClientAdapter::OnResetDialogState(CefRefPtr browser) { auto handler = _browserControl->JsDialogHandler; if (handler != nullptr) { auto browserWrapper = GetBrowserWrapper(browser->GetIdentifier(), browser->IsPopup()); handler->OnResetDialogState(_browserControl, browserWrapper); } } void ClientAdapter::OnDialogClosed(CefRefPtr browser) { auto handler = _browserControl->JsDialogHandler; if (handler != nullptr) { auto browserWrapper = GetBrowserWrapper(browser->GetIdentifier(), browser->IsPopup()); handler->OnDialogClosed(_browserControl, browserWrapper); } } bool ClientAdapter::OnFileDialog(CefRefPtr browser, FileDialogMode mode, const CefString& title, const CefString& default_file_path, const std::vector& accept_filters, const std::vector& accept_extensions, const std::vector& accept_descriptions, CefRefPtr callback) { auto handler = _browserControl->DialogHandler; if (handler == nullptr) { return false; } auto browserWrapper = GetBrowserWrapper(browser->GetIdentifier(), browser->IsPopup()); auto callbackWrapper = gcnew CefFileDialogCallbackWrapper(callback); return handler->OnFileDialog( _browserControl, browserWrapper, (CefFileDialogMode)mode, StringUtils::ToClr(title), StringUtils::ToClr(default_file_path), StringUtils::ToClr(accept_filters), StringUtils::ToClr(accept_extensions), StringUtils::ToClr(accept_descriptions), callbackWrapper); } bool ClientAdapter::OnDragEnter(CefRefPtr browser, CefRefPtr dragData, DragOperationsMask mask) { auto handler = _browserControl->DragHandler; if (handler == nullptr) { return false; } DragData dragDataWrapper(dragData); auto browserWrapper = GetBrowserWrapper(browser->GetIdentifier(), browser->IsPopup()); return handler->OnDragEnter(_browserControl, browserWrapper, %dragDataWrapper, (CefSharp::Enums::DragOperationsMask)mask); } void ClientAdapter::OnDraggableRegionsChanged(CefRefPtr browser, CefRefPtr frame, const std::vector& regions) { auto handler = _browserControl->DragHandler; if (handler != nullptr) { auto regionsList = TypeConversion::FromNative(regions); auto browserWrapper = GetBrowserWrapper(browser->GetIdentifier(), browser->IsPopup()); CefFrameWrapper frameWrapper(frame); return handler->OnDraggableRegionsChanged(_browserControl, browserWrapper, %frameWrapper, regionsList); } } bool ClientAdapter::CanDownload(CefRefPtr browser, const CefString& url, const CefString& request_method) { auto handler = _browserControl->DownloadHandler; if (handler == nullptr) { return true; } auto browserWrapper = GetBrowserWrapper(browser->GetIdentifier(), browser->IsPopup()); return handler->CanDownload(_browserControl, browserWrapper, StringUtils::ToClr(url), StringUtils::ToClr(request_method)); } bool ClientAdapter::OnBeforeDownload(CefRefPtr browser, CefRefPtr download_item, const CefString& suggested_name, CefRefPtr callback) { auto handler = _browserControl->DownloadHandler; if (handler == nullptr) { return false; } auto downloadItem = TypeConversion::FromNative(download_item); downloadItem->SuggestedFileName = StringUtils::ToClr(suggested_name); auto callbackWrapper = gcnew CefBeforeDownloadCallbackWrapper(callback); auto browserWrapper = GetBrowserWrapper(browser->GetIdentifier(), browser->IsPopup()); return handler->OnBeforeDownload(_browserControl, browserWrapper, downloadItem, callbackWrapper); }; void ClientAdapter::OnDownloadUpdated(CefRefPtr browser, CefRefPtr download_item, CefRefPtr callback) { auto handler = _browserControl->DownloadHandler; if (handler != nullptr) { auto callbackWrapper = gcnew CefDownloadItemCallbackWrapper(callback); auto browserWrapper = GetBrowserWrapper(browser->GetIdentifier(), browser->IsPopup()); handler->OnDownloadUpdated(_browserControl, browserWrapper, TypeConversion::FromNative(download_item), callbackWrapper); } } void ClientAdapter::OnFindResult(CefRefPtr browser, int identifier, int count, const CefRect& selectionRect, int activeMatchOrdinal, bool finalUpdate) { auto handler = _browserControl->FindHandler; if (handler != nullptr) { auto rect = Rect(selectionRect.x, selectionRect.y, selectionRect.width, selectionRect.height); auto browserWrapper = GetBrowserWrapper(browser->GetIdentifier(), browser->IsPopup()); handler->OnFindResult(_browserControl, browserWrapper, identifier, count, rect, activeMatchOrdinal, finalUpdate); } } bool ClientAdapter::GetAudioParameters(CefRefPtr browser, CefAudioParameters & params) { auto handler = _browserControl->AudioHandler; if (handler == nullptr) { return false; } auto browserWrapper = GetBrowserWrapper(browser->GetIdentifier(), browser->IsPopup()); auto parameters = new AudioParameters((CefSharp::Enums::ChannelLayout)params.channel_layout, params.sample_rate, params.frames_per_buffer); auto result = handler->GetAudioParameters(_browserControl, browserWrapper, *parameters); if (result) { params.channel_layout = (cef_channel_layout_t)parameters->ChannelLayout; params.sample_rate = parameters->SampleRate; params.frames_per_buffer = parameters->FramesPerBuffer; } return result; } void ClientAdapter::OnAudioStreamStarted(CefRefPtr browser, const CefAudioParameters& params, int channels) { auto handler = _browserControl->AudioHandler; if (handler != nullptr) { auto browserWrapper = GetBrowserWrapper(browser->GetIdentifier(), browser->IsPopup()); AudioParameters parameters((CefSharp::Enums::ChannelLayout)params.channel_layout, params.sample_rate, params.frames_per_buffer); handler->OnAudioStreamStarted(_browserControl, browserWrapper, parameters, channels); } } void ClientAdapter::OnAudioStreamPacket(CefRefPtr browser, const float** data, int frames, int64_t pts) { auto handler = _browserControl->AudioHandler; if (handler != nullptr) { auto browserWrapper = GetBrowserWrapper(browser->GetIdentifier(), browser->IsPopup()); handler->OnAudioStreamPacket(_browserControl, browserWrapper, IntPtr((void *)data), frames, pts); } } void ClientAdapter::OnAudioStreamStopped(CefRefPtr browser) { auto handler = _browserControl->AudioHandler; if (handler != nullptr) { auto browserWrapper = GetBrowserWrapper(browser->GetIdentifier(), browser->IsPopup()); handler->OnAudioStreamStopped(_browserControl, browserWrapper); } } void ClientAdapter::OnAudioStreamError(CefRefPtr browser, const CefString& message) { auto handler = _browserControl->AudioHandler; if (handler != nullptr) { auto browserWrapper = GetBrowserWrapper(browser->GetIdentifier(), browser->IsPopup()); handler->OnAudioStreamError(_browserControl, browserWrapper, StringUtils::ToClr(message)); } } void ClientAdapter::OnFrameCreated(CefRefPtr browser, CefRefPtr frame) { auto handler = _browserControl->FrameHandler; if (handler != nullptr) { auto browserWrapper = GetBrowserWrapper(browser->GetIdentifier(), browser->IsPopup()); auto frameWrapper = gcnew CefFrameWrapper(frame); if (browserWrapper == nullptr) { // Very first OnFrameCreated called may happen before OnAfterCreated // so we have to create a new wrapper that's lifespan is scoped to this single call. CefBrowserWrapper browserWrapper(browser); handler->OnFrameCreated(_browserControl, %browserWrapper, frameWrapper); } else { handler->OnFrameCreated(_browserControl, browserWrapper, frameWrapper); } } } void ClientAdapter::OnFrameAttached(CefRefPtr browser, CefRefPtr frame, bool reattached) { auto handler = _browserControl->FrameHandler; if (handler != nullptr) { auto browserWrapper = GetBrowserWrapper(browser->GetIdentifier(), browser->IsPopup()); CefFrameWrapper frameWrapper(frame); handler->OnFrameAttached(_browserControl, browserWrapper, % frameWrapper, reattached); } } void ClientAdapter::OnFrameDetached(CefRefPtr browser, CefRefPtr frame) { auto handler = _browserControl->FrameHandler; if (handler != nullptr) { auto browserWrapper = GetBrowserWrapper(browser->GetIdentifier(), browser->IsPopup()); CefFrameWrapper frameWrapper(frame); handler->OnFrameDetached(_browserControl, browserWrapper, % frameWrapper); } } void ClientAdapter::OnMainFrameChanged(CefRefPtr browser, CefRefPtr oldFrame, CefRefPtr newFrame) { auto handler = _browserControl->FrameHandler; if (handler != nullptr) { auto browserWrapper = GetBrowserWrapper(browser->GetIdentifier(), browser->IsPopup()); CefFrameWrapper^ oldFrameWrapper = nullptr; if (oldFrame.get()) { oldFrameWrapper = gcnew CefFrameWrapper(oldFrame); } CefFrameWrapper^ newFrameWrapper = nullptr; if (newFrame.get()) { newFrameWrapper = gcnew CefFrameWrapper(newFrame); } handler->OnMainFrameChanged(_browserControl, browserWrapper, oldFrameWrapper, newFrameWrapper); delete oldFrameWrapper; delete newFrameWrapper; } } bool ClientAdapter::OnShowPermissionPrompt(CefRefPtr browser, uint64_t prompt_id, const CefString& requesting_origin, uint32_t requested_permissions, CefRefPtr callback) { auto handler = _browserControl->PermissionHandler; if (handler != nullptr) { auto browserWrapper = GetBrowserWrapper(browser->GetIdentifier(), browser->IsPopup()); auto callbackWrapper = gcnew CefPermissionPromptCallbackWrapper(callback); return handler->OnShowPermissionPrompt(_browserControl, browserWrapper, prompt_id, StringUtils::ToClr(requesting_origin), (PermissionRequestType)requested_permissions, callbackWrapper); } return false; } void ClientAdapter::OnDismissPermissionPrompt(CefRefPtr browser, uint64_t prompt_id, cef_permission_request_result_t result) { auto handler = _browserControl->PermissionHandler; if (handler != nullptr) { auto browserWrapper = GetBrowserWrapper(browser->GetIdentifier(), browser->IsPopup()); handler->OnDismissPermissionPrompt(_browserControl, browserWrapper, prompt_id, (PermissionRequestResult)result); } } bool ClientAdapter::OnRequestMediaAccessPermission(CefRefPtr browser, CefRefPtr frame, const CefString& requesting_origin, uint32_t requested_permissions, CefRefPtr callback) { auto handler = _browserControl->PermissionHandler; if (handler != nullptr) { auto browserWrapper = GetBrowserWrapper(browser->GetIdentifier(), browser->IsPopup()); CefFrameWrapper frameWrapper(frame); auto callbackWrapper = gcnew CefMediaAccessCallbackWrapper(callback); return handler->OnRequestMediaAccessPermission(_browserControl, browserWrapper, %frameWrapper, StringUtils::ToClr(requesting_origin), (MediaAccessPermissionType)requested_permissions, callbackWrapper); } return false; } bool ClientAdapter::OnProcessMessageReceived(CefRefPtr browser, CefRefPtr frame, CefProcessId source_process, CefRefPtr message) { if (_disposed) { return true; } auto handled = false; auto name = message->GetName(); auto argList = message->GetArgumentList(); //TODO: JSB Rename messages (remove Root from name) if (name == kJavascriptRootObjectRequest) { auto browserAdapter = _browserAdapter; if (Object::ReferenceEquals(browserAdapter, nullptr) || browserAdapter->IsDisposed) { return true; } auto objectRepository = browserAdapter->JavascriptObjectRepository; if (objectRepository == nullptr) { return true; } auto callbackId = GetInt64(argList, 0); auto objectNames = argList->GetList(1); auto names = gcnew List(objectNames->GetSize()); for (size_t i = 0; i < objectNames->GetSize(); i++) { names->Add(StringUtils::ToClr(objectNames->GetString(i))); } //Call GetObjects with the list of names provided (will default to all if the list is empty //Previously we only sent a response if there were bound objects, now we always send //a response so the promise is resolved. auto objs = objectRepository->GetObjects(names); auto msg = CefProcessMessage::Create(kJavascriptRootObjectResponse); auto responseArgList = msg->GetArgumentList(); SetInt64(responseArgList, 0, callbackId); SerializeJsObjects(objs, responseArgList, 1); frame->SendProcessMessage(CefProcessId::PID_RENDERER, msg); handled = true; } else if (name == kJavascriptObjectsBoundInJavascript) { auto browserAdapter = _browserAdapter; if (Object::ReferenceEquals(browserAdapter, nullptr) || browserAdapter->IsDisposed) { return true; } auto objectRepository = browserAdapter->JavascriptObjectRepository; if (objectRepository == nullptr) { return true; } auto boundObjects = argList->GetList(0); auto objs = gcnew List^>(boundObjects->GetSize()); for (size_t i = 0; i < boundObjects->GetSize(); i++) { auto obj = boundObjects->GetDictionary(i); auto objectName = obj->GetString("Name"); auto alreadyBound = obj->GetBool("AlreadyBound"); auto isCached = obj->GetBool("IsCached"); objs->Add(Tuple::Create(StringUtils::ToClr(objectName), alreadyBound, isCached)); } objectRepository->ObjectsBound(objs); handled = true; } else if (name == kOnContextCreatedRequest) { //In certain circumstances the frame has already been destroyed by the time //we get here, only continue if we have a valid frame reference if (frame.get() && frame->IsValid()) { if (frame->IsMain()) { _browserControl->SetCanExecuteJavascriptOnMainFrame(StringUtils::ToClr(frame->GetIdentifier()), true); } auto handler = _browserControl->RenderProcessMessageHandler; if (handler != nullptr) { auto browserWrapper = GetBrowserWrapper(browser->GetIdentifier(), browser->IsPopup()); CefFrameWrapper frameWrapper(frame); handler->OnContextCreated(_browserControl, browserWrapper, %frameWrapper); } } handled = true; } else if (name == kOnContextReleasedRequest) { //In certain circumstances the frame has already been destroyed by the time //we get here, only continue if we have a valid frame reference if (frame.get() && frame->IsValid()) { if (frame->IsMain()) { _browserControl->SetCanExecuteJavascriptOnMainFrame(StringUtils::ToClr(frame->GetIdentifier()), false); } auto handler = _browserControl->RenderProcessMessageHandler; if (handler != nullptr) { auto browserWrapper = GetBrowserWrapper(browser->GetIdentifier(), browser->IsPopup()); CefFrameWrapper frameWrapper(frame); handler->OnContextReleased(_browserControl, browserWrapper, %frameWrapper); } } handled = true; } else if (name == kOnFocusedNodeChanged) { auto handler = _browserControl->RenderProcessMessageHandler; if (handler != nullptr) { IDomNode^ node = nullptr; // 0: is a node (bool) // 1: tag name (string) // 2: attributes (dictionary) auto browserWrapper = GetBrowserWrapper(browser->GetIdentifier(), browser->IsPopup()); CefFrameWrapper frameWrapper(frame); auto notEmpty = argList->GetBool(0); if (notEmpty) { // Node information was passed from the render process. auto tagName = StringUtils::ToClr(argList->GetString(1)); auto argAttributes = argList->GetDictionary(2); auto attributes = gcnew System::Collections::Generic::Dictionary(); CefDictionaryValue::KeyList keys; argAttributes->GetKeys(keys); for (auto key : keys) { attributes->Add(StringUtils::ToClr(key), StringUtils::ToClr(argAttributes->GetString(key))); } node = gcnew DomNode(tagName, attributes); } // DomNode will be empty if input focus was cleared handler->OnFocusedNodeChanged(_browserControl, browserWrapper, %frameWrapper, node); } } else if (name == kOnUncaughtException) { auto handler = _browserControl->RenderProcessMessageHandler; if (handler != nullptr) { auto browserWrapper = GetBrowserWrapper(browser->GetIdentifier(), browser->IsPopup()); CefFrameWrapper frameWrapper(frame); auto exception = gcnew JavascriptException(); exception->Message = StringUtils::ToClr(argList->GetString(0)); auto stackTrace = gcnew System::Collections::Generic::List(); auto argFrames = argList->GetList(1); for (auto i = 0; i < static_cast(argFrames->GetSize()); i++) { auto argFrame = argFrames->GetList(i); auto stackFrame = gcnew JavascriptStackFrame(); stackFrame->FunctionName = StringUtils::ToClr(argFrame->GetString(0)); stackFrame->LineNumber = argFrame->GetInt(1); stackFrame->ColumnNumber = argFrame->GetInt(2); stackFrame->SourceName = StringUtils::ToClr(argFrame->GetString(3)); stackTrace->Add(stackFrame); } exception->StackTrace = stackTrace->ToArray(); handler->OnUncaughtException(_browserControl, browserWrapper, %frameWrapper, exception); } } else if (name == kEvaluateJavascriptResponse || name == kJavascriptCallbackResponse) { auto browserAdapter = _browserAdapter; if (Object::ReferenceEquals(browserAdapter, nullptr) || browserAdapter->IsDisposed) { return true; } auto callbackFactory = browserAdapter->JavascriptCallbackFactory; auto success = argList->GetBool(0); auto callbackId = GetInt64(argList, 1); auto pendingTask = name == kEvaluateJavascriptResponse ? _pendingTaskRepository->RemovePendingTask(callbackId) : _pendingTaskRepository->RemoveJavascriptCallbackPendingTask(callbackId); if (pendingTask != nullptr) { auto response = gcnew JavascriptResponse(); response->Success = success; if (success) { response->Result = DeserializeObject(argList, 2, callbackFactory); } else { response->Message = StringUtils::ToClr(argList->GetString(2)); } pendingTask->TrySetResult(response); } handled = true; } else if (name == kJavascriptAsyncMethodCallRequest) { auto browserAdapter = _browserAdapter; if (Object::ReferenceEquals(browserAdapter, nullptr) || browserAdapter->IsDisposed) { return true; } auto callbackFactory = browserAdapter->JavascriptCallbackFactory; auto methodRunnerQueue = browserAdapter->MethodRunnerQueue; //Dispose is called on a different thread, so there's a chance //dispose is called after our IsDisposed checks, make sure we have //actual references. if (callbackFactory == nullptr || methodRunnerQueue == nullptr) { return true; } auto frameId = StringUtils::ToClr(frame->GetIdentifier()); auto objectId = GetInt64(argList, 0); auto callbackId = GetInt64(argList, 1); auto methodName = StringUtils::ToClr(argList->GetString(2)); auto arguments = argList->GetList(3); auto methodInvocation = gcnew MethodInvocation(browser->GetIdentifier(), frameId, objectId, methodName, (callbackId > 0 ? Nullable(callbackId) : Nullable())); for (auto i = 0; i < static_cast(arguments->GetSize()); i++) { methodInvocation->Parameters->Add(DeserializeObject(arguments, i, callbackFactory)); } methodRunnerQueue->Enqueue(methodInvocation); handled = true; } else if (name == kJavascriptMessageReceived) { auto browserAdapter = _browserAdapter; if (Object::ReferenceEquals(browserAdapter, nullptr) || browserAdapter->IsDisposed) { return true; } auto callbackFactory = browserAdapter->JavascriptCallbackFactory; //In certain circumstances the frame has already been destroyed by the time //we get here, only continue if we have a valid frame reference if (frame.get() && frame->IsValid()) { auto browserWrapper = GetBrowserWrapper(browser->GetIdentifier(), browser->IsPopup()); CefFrameWrapper frameWrapper(frame); auto deserializedMessage = DeserializeObject(argList, 0, callbackFactory); _browserControl->SetJavascriptMessageReceived(gcnew JavascriptMessageReceivedEventArgs(browserWrapper, %frameWrapper, deserializedMessage)); } handled = true; } return handled; } PendingTaskRepository^ ClientAdapter::GetPendingTaskRepository() { return _pendingTaskRepository; } void ClientAdapter::MethodInvocationComplete(MethodInvocationResult^ result) { auto browser = GetBrowserWrapper(result->BrowserId); if (result->CallbackId.HasValue && browser != nullptr && !browser->IsDisposed) { auto wrapper = static_cast(browser); if (wrapper == nullptr) { return; } auto cefBrowser = wrapper->Browser; if (cefBrowser.get()) { auto frame = cefBrowser->GetFrameByIdentifier(StringUtils::ToNative(result->FrameId)); if (frame.get() && frame->IsValid()) { auto message = CefProcessMessage::Create(kJavascriptAsyncMethodCallResponse); auto argList = message->GetArgumentList(); SetInt64(argList, 0, result->CallbackId.Value); argList->SetBool(1, result->Success); if (result->Success) { SerializeV8Object(argList, 2, result->Result, result->NameConverter); } else { argList->SetString(2, StringUtils::ToNative(result->Message)); } frame->SendProcessMessage(CefProcessId::PID_RENDERER, message); } } } } } }