From 2a08ace8e5e7243955a9e78206cffe89d68cffe0 Mon Sep 17 00:00:00 2001 From: Soumadeep Mazumdar Date: Wed, 29 Jan 2025 00:13:45 +0530 Subject: [PATCH] WebView2Samples update for 1.0.3079-prerelease (#264) * Updates for Win32, WPF, WinForms, UWP and WinUI3 sample apps from 134.0.3079.0 * Updated package version for Win32, WPF and WinForms sample apps to 1.0.3079-prerelease --------- Co-authored-by: WebView2 Github Bot --- SampleApps/WebView2APISample/AppWindow.cpp | 349 +++++++++++++++++- SampleApps/WebView2APISample/AppWindow.h | 20 + .../ScenarioDefaultBackgroundColor.cpp | 28 ++ .../ScenarioDefaultBackgroundColor.h | 17 + .../ScenarioDefaultBackgroundColor.html | 11 + .../ScenarioDragDropOverride.cpp | 135 +++++++ .../ScenarioDragDropOverride.h | 61 +++ .../ScenarioWebViewEventMonitor.cpp | 239 +++++++++--- .../ScenarioWebViewEventMonitor.h | 2 +- .../WebView2APISample/WebView2APISample.rc | 13 + .../WebView2APISample.vcxproj | 14 +- .../assets/ScenarioDragDropOverride.html | 108 ++++++ SampleApps/WebView2APISample/packages.config | 2 +- SampleApps/WebView2APISample/resource.h | 11 + .../WebView2WindowsFormsBrowser.csproj | 2 +- SampleApps/WebView2WpfBrowser/MainWindow.xaml | 2 + .../WebView2WpfBrowser/MainWindow.xaml.cs | 83 ++++- .../WebView2WpfBrowser.csproj | 2 +- .../WebView2_WinUI3_Sample/App.xaml.cs | 16 +- SampleApps/WebView2_WinUI3_Sample/readme.md | 51 +-- 20 files changed, 1041 insertions(+), 125 deletions(-) create mode 100644 SampleApps/WebView2APISample/ScenarioDefaultBackgroundColor.cpp create mode 100644 SampleApps/WebView2APISample/ScenarioDefaultBackgroundColor.h create mode 100644 SampleApps/WebView2APISample/ScenarioDefaultBackgroundColor.html create mode 100644 SampleApps/WebView2APISample/ScenarioDragDropOverride.cpp create mode 100644 SampleApps/WebView2APISample/ScenarioDragDropOverride.h create mode 100644 SampleApps/WebView2APISample/assets/ScenarioDragDropOverride.html diff --git a/SampleApps/WebView2APISample/AppWindow.cpp b/SampleApps/WebView2APISample/AppWindow.cpp index 3c9dbcd4..b1673c98 100644 --- a/SampleApps/WebView2APISample/AppWindow.cpp +++ b/SampleApps/WebView2APISample/AppWindow.cpp @@ -35,8 +35,10 @@ #include "ScenarioCustomDownloadExperience.h" #include "ScenarioCustomScheme.h" #include "ScenarioCustomSchemeNavigate.h" +#include "ScenarioDefaultBackgroundColor.h" #include "ScenarioDOMContentLoaded.h" #include "ScenarioDragDrop.h" +#include "ScenarioDragDropOverride.h" #include "ScenarioExtensionsManagement.h" #include "ScenarioFileSystemHandleShare.h" #include "ScenarioFileTypePolicy.h" @@ -201,7 +203,7 @@ AppWindow::AppWindow( WCHAR szTitle[s_maxLoadString]; // The title bar text LoadStringW(g_hInstance, IDS_APP_TITLE, szTitle, s_maxLoadString); m_appTitle = szTitle; - DWORD windowStyle = WS_OVERLAPPEDWINDOW; + DWORD windowStyle = WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN; if (userDataFolderParam.length() > 0) { m_userDataFolder = userDataFolderParam; @@ -684,6 +686,43 @@ bool AppWindow::ExecuteWebViewCommands(WPARAM wParam, LPARAM lParam) NewComponent(this); return true; } + case IDM_START_FIND: + { + std::wstring searchTerm = L"webview"; // Replace with the actual term + return Start(searchTerm); + } + case IDM_STOP_FIND: + { + return StopFind(); + } + case IDM_GET_MATCHES: + { + return GetMatchCount(); + } + case IDM_GET_ACTIVE_MATCH_INDEX: + { + return GetActiveMatchIndex(); + } + case IDC_FIND_TERM: + { + return FindTerm(); + } + case IDC_IS_CASE_SENSITIVE: + { + return IsCaseSensitive(); + } + case IDC_SHOULD_MATCH_WHOLE_WORD: + { + return ShouldMatchWord(); + } + case IDC_SHOULD_HIGHLIGHT_ALL_MATCHES: + { + return ShouldHighlightAllMatches(); + } + case IDC_SUPPRESS_DEFAULT_FIND_DIALOG: + { + return SuppressDefaultFindDialog(); + } } return false; } @@ -1210,6 +1249,302 @@ bool AppWindow::PrintToPdfStream() } //! [PrintToPdfStream] +//! [Start] +bool AppWindow::Start(const std::wstring& searchTerm) +{ + auto webView2Experimental29 = m_webView.try_query(); + CHECK_FEATURE_RETURN(webView2Experimental29); + + wil::com_ptr webView2find; + CHECK_FAILURE(webView2Experimental29->get_Find(&webView2find)); + SetupFindEventHandlers(webView2find); + + // Initialize find configuration/settings + if (!findOptions) + { + findOptions = SetDefaultFindOptions(); + } + + // Check if the search term has changed to determine if UI needs to be updated + if (m_findOnPageLastSearchTerm != searchTerm) + { + m_findOnPageLastSearchTerm = + searchTerm; // Update the last search term for future comparisons + } + + // Start the find operation + CHECK_FAILURE(webView2find->Start( + findOptions.get(), Callback( + [this](HRESULT result) -> HRESULT { return S_OK; }) + .Get())); + return true; +} +//! [Start] + +//! [FindNext] +bool AppWindow::FindNext() +{ + auto webView2Experimental29 = m_webView.try_query(); + CHECK_FEATURE_RETURN(webView2Experimental29); + wil::com_ptr webView2find; + CHECK_FAILURE(webView2Experimental29->get_Find(&webView2find)); + CHECK_FAILURE(webView2find->FindNext()); + + return true; +} +//! [FindNext] + +//! [FindPrevious] +bool AppWindow::FindPrevious() +{ + auto webView2Experimental29 = m_webView.try_query(); + CHECK_FEATURE_RETURN(webView2Experimental29); + wil::com_ptr webView2find; + CHECK_FAILURE(webView2Experimental29->get_Find(&webView2find)); + + CHECK_FAILURE(webView2find->FindPrevious()); + + return true; +} +//! [FindPrevious] + +//! [Stop] +bool AppWindow::StopFind() +{ + auto webView2Experimental29 = m_webView.try_query(); + CHECK_FEATURE_RETURN(webView2Experimental29); + wil::com_ptr webView2find; + CHECK_FAILURE(webView2Experimental29->get_Find(&webView2find)); + // Note, I am not 100% sure if this is the best way to remove the event handlers + // Because it would rely on the user clicking stopfind. Maybe put in destructor or when + // startfind completes? + CHECK_FAILURE(webView2find->remove_MatchCountChanged(m_matchCountChangedToken)); + CHECK_FAILURE(webView2find->remove_ActiveMatchIndexChanged(m_activeMatchIndexChangedToken)); + CHECK_FAILURE(webView2find->Stop()); + return true; +} +//! [Stop] + +//! [MatchCount] +bool AppWindow::GetMatchCount() +{ + auto webView2Experimental29 = m_webView.try_query(); + CHECK_FEATURE_RETURN(webView2Experimental29); + wil::com_ptr webView2find; + CHECK_FAILURE(webView2Experimental29->get_Find(&webView2find)); + int32_t matchCount; + CHECK_FAILURE(webView2find->get_MatchCount(&matchCount)); + + std::wstring matchCountStr = L"Match Count: " + std::to_wstring(matchCount); + MessageBox(m_mainWindow, matchCountStr.c_str(), L"Find Operation", MB_OK); + + return true; +} +//! [MatchCount] + +//! [ActiveMatchIndex] +bool AppWindow::GetActiveMatchIndex() +{ + auto webView2Experimental29 = m_webView.try_query(); + CHECK_FEATURE_RETURN(webView2Experimental29); + wil::com_ptr webView2find; + CHECK_FAILURE(webView2Experimental29->get_Find(&webView2find)); + int32_t activeMatchIndex; + CHECK_FAILURE(webView2find->get_ActiveMatchIndex(&activeMatchIndex)); + + std::wstring activeMatchIndexStr = + L"Active Match Index: " + std::to_wstring(activeMatchIndex); + MessageBox(m_mainWindow, activeMatchIndexStr.c_str(), L"Find Operation", MB_OK); + + return true; +} +//! [ActiveMatchIndex] + +//! [IsCaseSensitive] +bool AppWindow::IsCaseSensitive() +{ + auto webView2Experimental29 = m_webView.try_query(); + CHECK_FEATURE_RETURN(webView2Experimental29); + wil::com_ptr webView2find; + CHECK_FAILURE(webView2Experimental29->get_Find(&webView2find)); + + auto m_env18 = m_webViewEnvironment.try_query(); + CHECK_FEATURE_RETURN(m_env18); + CHECK_FAILURE(webView2find->Stop()); + + if (!findOptions) + { + findOptions = SetDefaultFindOptions(); + } + BOOL caseSensitive; + findOptions->get_IsCaseSensitive(&caseSensitive); + CHECK_FAILURE(findOptions->put_IsCaseSensitive(!caseSensitive)); + + CHECK_FAILURE(webView2find->Start( + findOptions.get(), Callback( + [this](HRESULT result) -> HRESULT { return S_OK; }) + .Get())); + return true; +} +//! [IsCaseSensitive] + +//! [ShouldHighlightAllMatches] +bool AppWindow::ShouldHighlightAllMatches() +{ + auto webView2Experimental29 = m_webView.try_query(); + CHECK_FEATURE_RETURN(webView2Experimental29); + wil::com_ptr webView2find; + CHECK_FAILURE(webView2Experimental29->get_Find(&webView2find)); + + auto m_env18 = m_webViewEnvironment.try_query(); + CHECK_FEATURE_RETURN(m_env18); + CHECK_FAILURE(webView2find->Stop()); + + if (!findOptions) + { + findOptions = SetDefaultFindOptions(); + } + BOOL shouldHighlightAllMatches; + CHECK_FAILURE(findOptions->get_ShouldHighlightAllMatches(&shouldHighlightAllMatches)); + CHECK_FAILURE(findOptions->put_ShouldHighlightAllMatches(!shouldHighlightAllMatches)); + CHECK_FAILURE(webView2find->Start( + findOptions.get(), Callback( + [this](HRESULT result) -> HRESULT { return S_OK; }) + .Get())); + return true; +} +//! [ShouldHighlightAllMatches] + +//! [ShouldMatchWord] +bool AppWindow::ShouldMatchWord() +{ + auto webView2Experimental29 = m_webView.try_query(); + CHECK_FEATURE_RETURN(webView2Experimental29); + wil::com_ptr webView2find; + CHECK_FAILURE(webView2Experimental29->get_Find(&webView2find)); + + auto m_env18 = m_webViewEnvironment.try_query(); + CHECK_FEATURE_RETURN(m_env18); + CHECK_FAILURE(webView2find->Stop()); + + if (!findOptions) + { + findOptions = SetDefaultFindOptions(); + } + BOOL shouldMatchWord; + findOptions->get_ShouldMatchWord(&shouldMatchWord); + CHECK_FAILURE(findOptions->put_ShouldMatchWord(!shouldMatchWord)); + CHECK_FAILURE(webView2find->Start( + findOptions.get(), Callback( + [this](HRESULT result) -> HRESULT { return S_OK; }) + .Get())); + return true; +} +//! [ShouldMatchWord] + +//! [SuppressDefaultFindDialog] +bool AppWindow::SuppressDefaultFindDialog() +{ + auto webView2Experimental29 = m_webView.try_query(); + CHECK_FEATURE_RETURN(webView2Experimental29); + wil::com_ptr webView2find; + CHECK_FAILURE(webView2Experimental29->get_Find(&webView2find)); + + auto m_env18 = m_webViewEnvironment.try_query(); + CHECK_FEATURE_RETURN(m_env18); + CHECK_FAILURE(webView2find->Stop()); + + if (!findOptions) + { + findOptions = SetDefaultFindOptions(); + } + BOOL suppressDefaultDialog; + findOptions->get_SuppressDefaultFindDialog(&suppressDefaultDialog); + CHECK_FAILURE(findOptions->put_SuppressDefaultFindDialog(!suppressDefaultDialog)); + CHECK_FAILURE(webView2find->Stop()); + CHECK_FAILURE(webView2find->Start( + findOptions.get(), Callback( + [this](HRESULT result) -> HRESULT { return S_OK; }) + .Get())); + return true; +} +//! [SuppressDefaultFindDialog] + +//! [FindTerm] +bool AppWindow::FindTerm() +{ + auto webView2Experimental29 = m_webView.try_query(); + CHECK_FEATURE_RETURN(webView2Experimental29); + wil::com_ptr webView2find; + CHECK_FAILURE(webView2Experimental29->get_Find(&webView2find)); + + TextInputDialog dialog( + GetMainWindow(), L"Find on Page Term", L"Find on Page Term:", L"Enter Find Term"); + + auto m_env18 = m_webViewEnvironment.try_query(); + CHECK_FEATURE_RETURN(m_env18); + CHECK_FAILURE(webView2find->Stop()); + + if (!findOptions) + { + findOptions = SetDefaultFindOptions(); + } + CHECK_FAILURE(findOptions->put_FindTerm(dialog.input.c_str())); + CHECK_FAILURE(webView2find->Start( + findOptions.get(), Callback( + [this](HRESULT result) -> HRESULT { return S_OK; }) + .Get())); + return true; +} +//! [FindTerm] + +wil::com_ptr AppWindow::SetDefaultFindOptions() +{ + auto m_env18 = m_webViewEnvironment.try_query(); + + // Initialize find configuration/settings + wil::com_ptr findOptions; + CHECK_FAILURE(m_env18->CreateFindOptions(&findOptions)); + CHECK_FAILURE(findOptions->put_FindTerm(L"Webview2")); + CHECK_FAILURE(findOptions->put_IsCaseSensitive(false)); + CHECK_FAILURE(findOptions->put_ShouldMatchWord(false)); + CHECK_FAILURE(findOptions->put_SuppressDefaultFindDialog(false)); + CHECK_FAILURE(findOptions->put_ShouldHighlightAllMatches(true)); + + return findOptions; +} + +void AppWindow::SetupFindEventHandlers(wil::com_ptr webView2find) +{ + CHECK_FAILURE(webView2find->add_MatchCountChanged( + Callback( + [this](ICoreWebView2ExperimentalFind* sender, IUnknown* args) -> HRESULT + { + int matchCount = 0; + if (sender) + { + CHECK_FAILURE(sender->get_MatchCount(&matchCount)); + } + return S_OK; + }) + .Get(), + &m_matchCountChangedToken)); + + CHECK_FAILURE(webView2find->add_ActiveMatchIndexChanged( + Callback( + [this](ICoreWebView2ExperimentalFind* sender, IUnknown* args) -> HRESULT + { + int activeIndex = -1; + if (sender) + { + CHECK_FAILURE(sender->get_ActiveMatchIndex(&activeIndex)); + } + return S_OK; + }) + .Get(), + &m_activeMatchIndexChangedToken)); +} + // Message handler for about dialog. INT_PTR CALLBACK AppWindow::About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { @@ -1523,6 +1858,18 @@ HRESULT AppWindow::CreateControllerWithOptions() } //! [AllowHostInputProcessing] + //! [DefaultBackgroundColor] + if (m_webviewOption.bg_color) + { + wil::com_ptr experimentalControllerOptions3; + if (SUCCEEDED(options->QueryInterface(IID_PPV_ARGS(&experimentalControllerOptions3)))) + { + CHECK_FAILURE( + experimentalControllerOptions3->put_DefaultBackgroundColor(*m_webviewOption.bg_color)); + } + } + //! [DefaultBackgroundColor] + if (m_dcompDevice || m_wincompCompositor) { //! [OnCreateCoreWebView2ControllerCompleted] diff --git a/SampleApps/WebView2APISample/AppWindow.h b/SampleApps/WebView2APISample/AppWindow.h index c00c694a..fdb20380 100644 --- a/SampleApps/WebView2APISample/AppWindow.h +++ b/SampleApps/WebView2APISample/AppWindow.h @@ -38,6 +38,7 @@ struct WebViewCreateOption // This value is inherited from the operated AppWindow WebViewCreateEntry entry = WebViewCreateEntry::OTHER; bool useOSRegion = false; + std::optional bg_color; WebViewCreateOption() { } @@ -210,6 +211,25 @@ class AppWindow SamplePrintSettings GetSelectedPrinterPrintSettings(std::wstring printerName); bool PrintToPdfStream(); void ToggleTrackingPrevention(); + bool Start(const std::wstring& searchTerm); + bool FindNext(); + bool FindPrevious(); + bool StopFind(); + bool GetMatchCount(); + bool GetActiveMatchIndex(); + bool FindTerm(); + bool ShouldHighlightAllMatches(); + bool ShouldMatchWord(); + bool SuppressDefaultFindDialog(); + bool IsCaseSensitive(); + wil::com_ptr SetDefaultFindOptions(); + void SetupFindEventHandlers(wil::com_ptr webView2find); + // Find on Page member + std::wstring m_findOnPageLastSearchTerm; + wil::com_ptr findOptions; + EventRegistrationToken m_activeMatchIndexChangedToken = {}; + EventRegistrationToken m_matchCountChangedToken = {}; + std::wstring GetLocalPath(std::wstring path, bool keep_exe_path); void DeleteAllComponents(); diff --git a/SampleApps/WebView2APISample/ScenarioDefaultBackgroundColor.cpp b/SampleApps/WebView2APISample/ScenarioDefaultBackgroundColor.cpp new file mode 100644 index 00000000..33491f75 --- /dev/null +++ b/SampleApps/WebView2APISample/ScenarioDefaultBackgroundColor.cpp @@ -0,0 +1,28 @@ +#include "stdafx.h" + +#include "AppWindow.h" +#include "CheckFailure.h" +#include "ScenarioDefaultBackgroundColor.h" +#include +#include + +using namespace Microsoft::WRL; +using namespace std; + +static constexpr wchar_t c_samplePath[] = L"ScenarioDefaultBackgroundColor.html"; + +ScenarioDefaultBackgroundColor::ScenarioDefaultBackgroundColor(AppWindow* appWindow) +{ + std::wstring sampleUri = appWindow->GetLocalUri(c_samplePath); + WebViewCreateOption options = appWindow->GetWebViewOption(); + + options.bg_color = {255, 225, 0, 225}; + AppWindow* appWindowWco = new AppWindow(appWindow->GetCreationModeId(), options, sampleUri); + // Delete this component when the window closes. + appWindowWco->SetOnAppWindowClosing([this, appWindow] + { appWindow->DeleteComponent(this); }); +} + +ScenarioDefaultBackgroundColor::~ScenarioDefaultBackgroundColor() +{ +} \ No newline at end of file diff --git a/SampleApps/WebView2APISample/ScenarioDefaultBackgroundColor.h b/SampleApps/WebView2APISample/ScenarioDefaultBackgroundColor.h new file mode 100644 index 00000000..2c71f0ff --- /dev/null +++ b/SampleApps/WebView2APISample/ScenarioDefaultBackgroundColor.h @@ -0,0 +1,17 @@ +// Copyright (C) Microsoft Corporation. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#pragma once + +#include "stdafx.h" + +#include "ComponentBase.h" +#include + +class ScenarioDefaultBackgroundColor : public ComponentBase +{ +public: + ScenarioDefaultBackgroundColor(AppWindow* appWindow); + ~ScenarioDefaultBackgroundColor() override; +}; diff --git a/SampleApps/WebView2APISample/ScenarioDefaultBackgroundColor.html b/SampleApps/WebView2APISample/ScenarioDefaultBackgroundColor.html new file mode 100644 index 00000000..bcda4fdc --- /dev/null +++ b/SampleApps/WebView2APISample/ScenarioDefaultBackgroundColor.html @@ -0,0 +1,11 @@ + + + + + + WebView with CoreWebViewControllerOptions.DefaultBackgroundColor + + +

CoreWebViewControllerOptions.DefaultBackgroundColor

+ + \ No newline at end of file diff --git a/SampleApps/WebView2APISample/ScenarioDragDropOverride.cpp b/SampleApps/WebView2APISample/ScenarioDragDropOverride.cpp new file mode 100644 index 00000000..12de19a3 --- /dev/null +++ b/SampleApps/WebView2APISample/ScenarioDragDropOverride.cpp @@ -0,0 +1,135 @@ +// Copyright (C) Microsoft Corporation. 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 "CheckFailure.h" + +#include "ScenarioDragDropOverride.h" +using namespace Microsoft::WRL; + +static constexpr WCHAR c_samplePath[] = L"ScenarioDragDropOverride.html"; +static constexpr WCHAR c_webmessageDefault[] = L"default"; +static constexpr WCHAR c_webmessageOverride[] = L"override"; +static constexpr WCHAR c_webmessageNoop[] = L"noop"; + +ScenarioDragDropOverride::ScenarioDragDropOverride(AppWindow* appWindow) + : m_appWindow(appWindow) +{ + m_sampleUri = m_appWindow->GetLocalUri(c_samplePath); + m_webView = m_appWindow->GetWebView(); + wil::com_ptr controller = appWindow->GetWebViewController(); + wil::com_ptr compController = + controller.try_query(); + if (!compController) + { + return; + } + + m_compControllerExperimental6 = + compController.try_query(); + if (!m_compControllerExperimental6) + { + return; + } + + CHECK_FAILURE(m_webView->add_WebMessageReceived( + Microsoft::WRL::Callback( + [this](ICoreWebView2* sender, ICoreWebView2WebMessageReceivedEventArgs* args) + { + wil::unique_cotaskmem_string uri; + CHECK_FAILURE(args->get_Source(&uri)); + + // Always validate that the origin of the message is what you expect. + if (uri.get() != m_sampleUri) + { + return S_OK; + } + wil::unique_cotaskmem_string messageRaw; + CHECK_FAILURE(args->TryGetWebMessageAsString(&messageRaw)); + std::wstring message = messageRaw.get(); + + if (message == c_webmessageDefault) + { + m_dragOverrideMode = DragOverrideMode::DEFAULT; + } + else if (message == c_webmessageOverride) + { + m_dragOverrideMode = DragOverrideMode::OVERRIDE; + } + else if (message == c_webmessageNoop) + { + m_dragOverrideMode = DragOverrideMode::NOOP; + } + + return S_OK; + }) + .Get(), + &m_webMessageReceivedToken)); + + //! [DragStarting] + // Using DragStarting to simply make a synchronous DoDragDrop call instead of + // having WebView2 do it. + CHECK_FAILURE(m_compControllerExperimental6->add_DragStarting( + Callback( + [this]( + ICoreWebView2CompositionController* sender, + ICoreWebView2ExperimentalDragStartingEventArgs* args) + { + if (m_dragOverrideMode != DragOverrideMode::OVERRIDE) + { + // If the event is marked handled, WebView2 will not execute its drag logic. + args->put_Handled(m_dragOverrideMode == DragOverrideMode::NOOP); + return S_OK; + } + + wil::com_ptr dragData; + DWORD okEffects = DROPEFFECT_NONE; + CHECK_FAILURE(args->get_AllowedDropEffects(&okEffects)); + CHECK_FAILURE(args->get_Data(&dragData)); + + // This member refers to an implementation of IDropSource. It is an + // OLE interface that is necessary to initiate drag in an application. + // https://learn.microsoft.com/en-us/windows/win32/api/oleidl/nn-oleidl-idropsource + if (!m_dropSource) + { + m_dropSource = Make(); + } + + DWORD effect = DROPEFFECT_NONE; + HRESULT hr = DoDragDrop(dragData.get(), m_dropSource.get(), okEffects, &effect); + args->put_Handled(TRUE); + + return hr; + }) + .Get(), + &m_dragStartingToken)); + //! [DragStarting] + + CHECK_FAILURE(m_webView->add_ContentLoading( + Callback( + [this](ICoreWebView2* sender, ICoreWebView2ContentLoadingEventArgs* args) -> HRESULT + { + wil::unique_cotaskmem_string uri; + sender->get_Source(&uri); + if (uri.get() != m_sampleUri) + { + m_appWindow->DeleteComponent(this); + } + return S_OK; + }) + .Get(), + &m_contentLoadingToken)); + + CHECK_FAILURE(m_webView->Navigate(m_sampleUri.c_str())); +} + +ScenarioDragDropOverride::~ScenarioDragDropOverride() +{ + if (m_compControllerExperimental6) + { + CHECK_FAILURE(m_compControllerExperimental6->remove_DragStarting(m_dragStartingToken)); + } + CHECK_FAILURE(m_webView->remove_WebMessageReceived(m_webMessageReceivedToken)); + CHECK_FAILURE(m_webView->remove_ContentLoading(m_contentLoadingToken)); +} diff --git a/SampleApps/WebView2APISample/ScenarioDragDropOverride.h b/SampleApps/WebView2APISample/ScenarioDragDropOverride.h new file mode 100644 index 00000000..ff8e1c64 --- /dev/null +++ b/SampleApps/WebView2APISample/ScenarioDragDropOverride.h @@ -0,0 +1,61 @@ +// Copyright (C) Microsoft Corporation. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#pragma once +#include "stdafx.h" + +#include "AppWindow.h" +#include "ComponentBase.h" + +class ScenarioDragDropOverride : public ComponentBase +{ +public: + ScenarioDragDropOverride(AppWindow* appWindow); + ~ScenarioDragDropOverride() override; + +private: + // Barebones IDropSource implementation to serve the example drag drop override. + class ScenarioDragDropOverrideDropSource + : public Microsoft::WRL::RuntimeClass< + Microsoft::WRL::RuntimeClassFlags, IDropSource> + { + public: + // IDropSource implementation: + STDMETHODIMP QueryContinueDrag(BOOL escapePressed, DWORD keyState) override + { + if (escapePressed) + { + return DRAGDROP_S_CANCEL; + } + if (!(keyState & (MK_LBUTTON | MK_RBUTTON))) + { + return DRAGDROP_S_DROP; + } + return S_OK; + } + + STDMETHODIMP GiveFeedback(DWORD dwEffect) override + { + return DRAGDROP_S_USEDEFAULTCURSORS; + } + }; + + enum class DragOverrideMode + { + DEFAULT = 0, + OVERRIDE = 1, + NOOP = 2, + }; + + EventRegistrationToken m_dragStartingToken = {}; + EventRegistrationToken m_webMessageReceivedToken = {}; + EventRegistrationToken m_contentLoadingToken = {}; + + AppWindow* m_appWindow = nullptr; + std::wstring m_sampleUri; + wil::com_ptr m_webView = nullptr; + wil::com_ptr m_compControllerExperimental6; + wil::com_ptr m_dropSource; + DragOverrideMode m_dragOverrideMode = DragOverrideMode::DEFAULT; +}; \ No newline at end of file diff --git a/SampleApps/WebView2APISample/ScenarioWebViewEventMonitor.cpp b/SampleApps/WebView2APISample/ScenarioWebViewEventMonitor.cpp index 11a7d544..23dabe0e 100644 --- a/SampleApps/WebView2APISample/ScenarioWebViewEventMonitor.cpp +++ b/SampleApps/WebView2APISample/ScenarioWebViewEventMonitor.cpp @@ -20,6 +20,7 @@ using namespace Microsoft::WRL; using namespace std; static constexpr wchar_t c_samplePath[] = L"ScenarioWebViewEventMonitor.html"; +const int first_level_iframe_depth = 1; std::wstring WebResourceSourceToString(COREWEBVIEW2_WEB_RESOURCE_REQUEST_SOURCE_KINDS source) { @@ -456,8 +457,10 @@ void ScenarioWebViewEventMonitor::EnableWebResourceResponseReceivedEvent(bool en { m_webviewEventSource2->add_WebResourceResponseReceived( Callback( - [this](ICoreWebView2* webview, ICoreWebView2WebResourceResponseReceivedEventArgs* args) - -> HRESULT { + [this]( + ICoreWebView2* webview, + ICoreWebView2WebResourceResponseReceivedEventArgs* args) noexcept -> HRESULT + { wil::com_ptr webResourceRequest; CHECK_FAILURE(args->get_Request(&webResourceRequest)); wil::com_ptr @@ -513,8 +516,10 @@ void ScenarioWebViewEventMonitor::EnableWebResourceRequestedEvent(bool enable) m_webviewEventSource->add_WebResourceRequested( Callback( - [this](ICoreWebView2* webview, ICoreWebView2WebResourceRequestedEventArgs* args) - -> HRESULT { + [this]( + ICoreWebView2* webview, + ICoreWebView2WebResourceRequestedEventArgs* args) noexcept -> HRESULT + { wil::com_ptr webResourceRequest; CHECK_FAILURE(args->get_Request(&webResourceRequest)); wil::com_ptr webResourceResponse; @@ -560,8 +565,10 @@ void ScenarioWebViewEventMonitor::InitializeEventView(ICoreWebView2* webviewEven m_webviewEventView->add_WebMessageReceived( Callback( - [this](ICoreWebView2* sender, ICoreWebView2WebMessageReceivedEventArgs* args) - -> HRESULT { + [this]( + ICoreWebView2* sender, + ICoreWebView2WebMessageReceivedEventArgs* args) noexcept -> HRESULT + { wil::unique_cotaskmem_string source; CHECK_FAILURE(args->get_Source(&source)); wil::unique_cotaskmem_string webMessageAsString; @@ -596,8 +603,10 @@ void ScenarioWebViewEventMonitor::InitializeEventView(ICoreWebView2* webviewEven m_webviewEventSource->add_WebMessageReceived( Callback( - [this](ICoreWebView2* sender, ICoreWebView2WebMessageReceivedEventArgs* args) - -> HRESULT { + [this]( + ICoreWebView2* sender, + ICoreWebView2WebMessageReceivedEventArgs* args) noexcept -> HRESULT + { wil::unique_cotaskmem_string source; CHECK_FAILURE(args->get_Source(&source)); wil::unique_cotaskmem_string webMessageAsString; @@ -633,8 +642,10 @@ void ScenarioWebViewEventMonitor::InitializeEventView(ICoreWebView2* webviewEven m_webviewEventSource->add_NewWindowRequested( Callback( - [this](ICoreWebView2* sender, ICoreWebView2NewWindowRequestedEventArgs* args) - -> HRESULT { + [this]( + ICoreWebView2* sender, + ICoreWebView2NewWindowRequestedEventArgs* args) noexcept -> HRESULT + { BOOL handled = FALSE; CHECK_FAILURE(args->get_Handled(&handled)); BOOL isUserInitiated = FALSE; @@ -647,7 +658,8 @@ void ScenarioWebViewEventMonitor::InitializeEventView(ICoreWebView2* webviewEven wil::unique_cotaskmem_string name; std::wstring encodedName = EncodeQuote(L""); - if (SUCCEEDED(args->QueryInterface(IID_PPV_ARGS(&args2)))) { + if (SUCCEEDED(args->QueryInterface(IID_PPV_ARGS(&args2)))) + { CHECK_FAILURE(args2->get_Name(&name)); encodedName = EncodeQuote(name.get()); } @@ -698,8 +710,10 @@ void ScenarioWebViewEventMonitor::InitializeEventView(ICoreWebView2* webviewEven m_webviewEventSource->add_NavigationStarting( Callback( - [this](ICoreWebView2* sender, ICoreWebView2NavigationStartingEventArgs* args) - -> HRESULT { + [this]( + ICoreWebView2* sender, + ICoreWebView2NavigationStartingEventArgs* args) noexcept -> HRESULT + { std::wstring message = NavigationStartingArgsToJsonString(sender, args, L"NavigationStarting"); PostEventMessage(message); @@ -711,8 +725,10 @@ void ScenarioWebViewEventMonitor::InitializeEventView(ICoreWebView2* webviewEven m_webviewEventSource->add_FrameNavigationStarting( Callback( - [this](ICoreWebView2* sender, ICoreWebView2NavigationStartingEventArgs* args) - -> HRESULT { + [this]( + ICoreWebView2* sender, + ICoreWebView2NavigationStartingEventArgs* args) noexcept -> HRESULT + { std::wstring message = NavigationStartingArgsToJsonString( sender, args, L"FrameNavigationStarting"); PostEventMessage(message); @@ -724,8 +740,9 @@ void ScenarioWebViewEventMonitor::InitializeEventView(ICoreWebView2* webviewEven m_webviewEventSource->add_SourceChanged( Callback( - [this](ICoreWebView2* sender, ICoreWebView2SourceChangedEventArgs* args) - -> HRESULT { + [this](ICoreWebView2* sender, ICoreWebView2SourceChangedEventArgs* args) noexcept + -> HRESULT + { BOOL isNewDocument = FALSE; CHECK_FAILURE(args->get_IsNewDocument(&isNewDocument)); @@ -742,9 +759,9 @@ void ScenarioWebViewEventMonitor::InitializeEventView(ICoreWebView2* webviewEven m_webviewEventSource->add_ContentLoading( Callback( - [this]( - ICoreWebView2* sender, - ICoreWebView2ContentLoadingEventArgs* args) -> HRESULT { + [this](ICoreWebView2* sender, ICoreWebView2ContentLoadingEventArgs* args) noexcept + -> HRESULT + { std::wstring message = ContentLoadingArgsToJsonString(sender, args, L"ContentLoading"); PostEventMessage(message); @@ -756,7 +773,8 @@ void ScenarioWebViewEventMonitor::InitializeEventView(ICoreWebView2* webviewEven m_webviewEventSource->add_HistoryChanged( Callback( - [this](ICoreWebView2* sender, IUnknown* args) -> HRESULT { + [this](ICoreWebView2* sender, IUnknown* args) noexcept -> HRESULT + { std::wstring message = L"{ \"kind\": \"event\", \"name\": \"HistoryChanged\", \"args\": {"; message += @@ -770,8 +788,10 @@ void ScenarioWebViewEventMonitor::InitializeEventView(ICoreWebView2* webviewEven m_webviewEventSource->add_NavigationCompleted( Callback( - [this](ICoreWebView2* sender, ICoreWebView2NavigationCompletedEventArgs* args) - -> HRESULT { + [this]( + ICoreWebView2* sender, + ICoreWebView2NavigationCompletedEventArgs* args) noexcept -> HRESULT + { std::wstring message = NavigationCompletedArgsToJsonString(sender, args, L"NavigationCompleted"); PostEventMessage(message); @@ -781,10 +801,12 @@ void ScenarioWebViewEventMonitor::InitializeEventView(ICoreWebView2* webviewEven .Get(), &m_navigationCompletedToken); - m_webviewEventSource->add_FrameNavigationCompleted( + m_webviewEventSource->add_FrameNavigationCompleted( Callback( - [this](ICoreWebView2* sender, ICoreWebView2NavigationCompletedEventArgs* args) - -> HRESULT { + [this]( + ICoreWebView2* sender, + ICoreWebView2NavigationCompletedEventArgs* args) noexcept -> HRESULT + { std::wstring message = NavigationCompletedArgsToJsonString( sender, args, L"FrameNavigationCompleted"); PostEventMessage(message); @@ -796,8 +818,9 @@ void ScenarioWebViewEventMonitor::InitializeEventView(ICoreWebView2* webviewEven m_webviewEventSource2->add_DOMContentLoaded( Callback( - [this](ICoreWebView2* sender, ICoreWebView2DOMContentLoadedEventArgs* args) - -> HRESULT { + [this](ICoreWebView2* sender, ICoreWebView2DOMContentLoadedEventArgs* args) noexcept + -> HRESULT + { std::wstring message = DOMContentLoadedArgsToJsonString(sender, args, L"DOMContentLoaded"); PostEventMessage(message); @@ -809,7 +832,8 @@ void ScenarioWebViewEventMonitor::InitializeEventView(ICoreWebView2* webviewEven m_webviewEventSource->add_DocumentTitleChanged( Callback( - [this](ICoreWebView2* sender, IUnknown* args) -> HRESULT { + [this](ICoreWebView2* sender, IUnknown* args) noexcept -> HRESULT + { std::wstring message = L"{ \"kind\": \"event\", \"name\": \"DocumentTitleChanged\", \"args\": {" L"}" + @@ -826,8 +850,10 @@ void ScenarioWebViewEventMonitor::InitializeEventView(ICoreWebView2* webviewEven if (m_webviewEventSource4) { m_webviewEventSource4->add_DownloadStarting( Callback( - [this](ICoreWebView2* sender, ICoreWebView2DownloadStartingEventArgs* args) - -> HRESULT { + [this]( + ICoreWebView2* sender, + ICoreWebView2DownloadStartingEventArgs* args) noexcept -> HRESULT + { wil::com_ptr download; CHECK_FAILURE(args->get_DownloadOperation(&download)); @@ -860,8 +886,8 @@ void ScenarioWebViewEventMonitor::InitializeEventView(ICoreWebView2* webviewEven Callback( [this, download]( ICoreWebView2DownloadOperation* sender, - IUnknown* args) - -> HRESULT { + IUnknown* args) noexcept -> HRESULT + { COREWEBVIEW2_DOWNLOAD_STATE state; CHECK_FAILURE(download->get_State(&state)); @@ -907,10 +933,11 @@ void ScenarioWebViewEventMonitor::InitializeEventView(ICoreWebView2* webviewEven &m_stateChangedToken); download->add_BytesReceivedChanged( - Callback< - ICoreWebView2BytesReceivedChangedEventHandler>( + Callback( [this, download]( - ICoreWebView2DownloadOperation* sender, IUnknown* args) -> HRESULT { + ICoreWebView2DownloadOperation* sender, + IUnknown* args) noexcept -> HRESULT + { INT64 bytesReceived = 0; CHECK_FAILURE(download->get_BytesReceived( &bytesReceived)); @@ -934,7 +961,9 @@ void ScenarioWebViewEventMonitor::InitializeEventView(ICoreWebView2* webviewEven download->add_EstimatedEndTimeChanged( Callback( [this, download]( - ICoreWebView2DownloadOperation* sender, IUnknown* args) -> HRESULT { + ICoreWebView2DownloadOperation* sender, + IUnknown* args) noexcept -> HRESULT + { wil::unique_cotaskmem_string estimatedEndTime; CHECK_FAILURE(download->get_EstimatedEndTime(&estimatedEndTime)); @@ -977,11 +1006,12 @@ void ScenarioWebViewEventMonitor::InitializeEventView(ICoreWebView2* webviewEven m_webviewEventSource4->add_FrameCreated( Callback( - [this](ICoreWebView2* sender, ICoreWebView2FrameCreatedEventArgs* args) - -> HRESULT { + [this](ICoreWebView2* sender, ICoreWebView2FrameCreatedEventArgs* args) noexcept + -> HRESULT + { wil::com_ptr webviewFrame; CHECK_FAILURE(args->get_Frame(&webviewFrame)); - InitializeFrameEventView(webviewFrame); + InitializeFrameEventView(webviewFrame, first_level_iframe_depth + 1); wil::unique_cotaskmem_string name; CHECK_FAILURE(webviewFrame->get_Name(&name)); @@ -989,8 +1019,7 @@ void ScenarioWebViewEventMonitor::InitializeEventView(ICoreWebView2* webviewEven L"{ \"kind\": \"event\", \"name\": \"FrameCreated\", \"args\": {"; message += L"\"frame\": " + EncodeQuote(name.get()); - auto webView2_20 = - wil::com_ptr(sender).try_query(); + auto webView2_20 = wil::try_com_query(sender); if (webView2_20) { UINT32 frameId = 0; @@ -1017,8 +1046,8 @@ void ScenarioWebViewEventMonitor::InitializeEventView(ICoreWebView2* webviewEven m_controllerEventSource->add_GotFocus( Callback( - [this](ICoreWebView2Controller* sender, IUnknown* args) - -> HRESULT { + [this](ICoreWebView2Controller* sender, IUnknown* args) noexcept -> HRESULT + { std::wstring message = L"{ \"kind\": \"event\", \"name\": \"GotFocus\", \"args\": {} }"; PostEventMessage(message); @@ -1028,8 +1057,8 @@ void ScenarioWebViewEventMonitor::InitializeEventView(ICoreWebView2* webviewEven &m_gotFocusToken); m_controllerEventSource->add_LostFocus( Callback( - [this](ICoreWebView2Controller* sender, IUnknown* args) - -> HRESULT { + [this](ICoreWebView2Controller* sender, IUnknown* args) noexcept -> HRESULT + { std::wstring message = L"{ \"kind\": \"event\", \"name\": \"LostFocus\", \"args\": {} }"; PostEventMessage(message); @@ -1043,8 +1072,8 @@ void ScenarioWebViewEventMonitor::InitializeEventView(ICoreWebView2* webviewEven { m_webViewEventSource9->add_IsDefaultDownloadDialogOpenChanged( Callback( - [this]( - ICoreWebView2* sender, IUnknown* args) -> HRESULT { + [this](ICoreWebView2* sender, IUnknown* args) noexcept -> HRESULT + { std::wstring message = L"{ \"kind\": \"event\", \"name\": " L"\"IsDefaultDownloadDialogOpenChanged\", \"args\": {"; @@ -1062,8 +1091,9 @@ void ScenarioWebViewEventMonitor::InitializeEventView(ICoreWebView2* webviewEven m_webviewEventSource->add_PermissionRequested( Callback( - [this](ICoreWebView2* sender, ICoreWebView2PermissionRequestedEventArgs* args) - -> HRESULT + [this]( + ICoreWebView2* sender, + ICoreWebView2PermissionRequestedEventArgs* args) noexcept -> HRESULT { wil::unique_cotaskmem_string uri; CHECK_FAILURE(args->get_Uri(&uri)); @@ -1095,13 +1125,17 @@ void ScenarioWebViewEventMonitor::InitializeEventView(ICoreWebView2* webviewEven } void ScenarioWebViewEventMonitor::InitializeFrameEventView( - wil::com_ptr webviewFrame) + wil::com_ptr webviewFrame, int depth) { webviewFrame->add_Destroyed( Callback( - [this](ICoreWebView2Frame* sender, IUnknown* args) -> HRESULT { + [this](ICoreWebView2Frame* sender, IUnknown* args) noexcept -> HRESULT + { + wil::unique_cotaskmem_string name; + CHECK_FAILURE(sender->get_Name(&name)); std::wstring message = L"{ \"kind\": \"event\", \"name\": " L"\"CoreWebView2Frame::Destroyed\", \"args\": {"; + message += L"\"frame name\": " + EncodeQuote(name.get()); message += L"}" + WebViewPropertiesToJsonString(m_webviewEventSource.get()) + L"}"; PostEventMessage(message); @@ -1117,7 +1151,8 @@ void ScenarioWebViewEventMonitor::InitializeFrameEventView( Callback( [this]( ICoreWebView2Frame* sender, - ICoreWebView2NavigationStartingEventArgs* args) -> HRESULT { + ICoreWebView2NavigationStartingEventArgs* args) noexcept -> HRESULT + { std::wstring message = NavigationStartingArgsToJsonString( m_webviewEventSource.get(), args, L"CoreWebView2Frame::NavigationStarting"); @@ -1130,8 +1165,10 @@ void ScenarioWebViewEventMonitor::InitializeFrameEventView( frame2->add_ContentLoading( Callback( - [this](ICoreWebView2Frame* sender, ICoreWebView2ContentLoadingEventArgs* args) - -> HRESULT { + [this]( + ICoreWebView2Frame* sender, + ICoreWebView2ContentLoadingEventArgs* args) noexcept -> HRESULT + { std::wstring message = ContentLoadingArgsToJsonString( m_webviewEventSource.get(), args, L"CoreWebView2Frame::ContentLoading"); PostEventMessage(message); @@ -1145,7 +1182,8 @@ void ScenarioWebViewEventMonitor::InitializeFrameEventView( Callback( [this]( ICoreWebView2Frame* sender, - ICoreWebView2NavigationCompletedEventArgs* args) -> HRESULT { + ICoreWebView2NavigationCompletedEventArgs* args) noexcept -> HRESULT + { std::wstring message = NavigationCompletedArgsToJsonString( m_webviewEventSource.get(), args, L"CoreWebView2Frame::NavigationCompleted"); @@ -1158,8 +1196,10 @@ void ScenarioWebViewEventMonitor::InitializeFrameEventView( frame2->add_DOMContentLoaded( Callback( - [this](ICoreWebView2Frame* sender, ICoreWebView2DOMContentLoadedEventArgs* args) - -> HRESULT { + [this]( + ICoreWebView2Frame* sender, + ICoreWebView2DOMContentLoadedEventArgs* args) noexcept -> HRESULT + { std::wstring message = DOMContentLoadedArgsToJsonString( m_webviewEventSource.get(), args, L"CoreWebView2Frame::DOMContentLoaded"); @@ -1169,6 +1209,89 @@ void ScenarioWebViewEventMonitor::InitializeFrameEventView( }) .Get(), NULL); + frame2->add_WebMessageReceived( + Callback( + [this]( + ICoreWebView2Frame* sender, + ICoreWebView2WebMessageReceivedEventArgs* args) noexcept -> HRESULT + { + wil::unique_cotaskmem_string source; + CHECK_FAILURE(args->get_Source(&source)); + wil::unique_cotaskmem_string webMessageAsString; + if (SUCCEEDED(args->TryGetWebMessageAsString(&webMessageAsString))) + { + std::wstring message = + L"{ \"kind\": \"event\", \"name\": " + L"\"CoreWebView2Frame::WebMessageReceived\", \"args\": {"; + + wil::unique_cotaskmem_string uri; + CHECK_FAILURE(args->get_Source(&uri)); + message += L"\"source\": " + EncodeQuote(uri.get()) + L", "; + message += L"\"webMessageAsString\": " + + EncodeQuote(webMessageAsString.get()) + L" "; + + UINT32 frameId = 0; + auto frame5 = wil::try_com_query(sender); + if (frame5) + { + CHECK_FAILURE(frame5->get_FrameId(&frameId)); + message += L",\"sender webview frame id\": " + + std::to_wstring((int)frameId); + } + message += L"}" + + WebViewPropertiesToJsonString(m_webviewEventSource.get()) + + L"}"; + PostEventMessage(message); + } + + return S_OK; + }) + .Get(), + NULL); + } + auto experimental_frame8 = webviewFrame.try_query(); + if (experimental_frame8) + { + //! [FrameCreated] + experimental_frame8->add_FrameCreated( + Callback( + [this, depth]( + ICoreWebView2Frame* sender, + ICoreWebView2FrameCreatedEventArgs* args) noexcept -> HRESULT + { + wil::com_ptr webviewFrame; + CHECK_FAILURE(args->get_Frame(&webviewFrame)); + wil::unique_cotaskmem_string name; + CHECK_FAILURE(webviewFrame->get_Name(&name)); + + InitializeFrameEventView(webviewFrame, depth + 1); + + std::wstring message = L"{ \"kind\": \"event\", \"name\": " + L"\"CoreWebView2Frame::FrameCreated\", \"args\": {"; + message += L"\"frame name\": " + EncodeQuote(name.get()); + message += L",\"depth\": " + std::to_wstring(depth); + auto frame5 = webviewFrame.try_query(); + UINT32 frameId = 0; + if (frame5) + { + CHECK_FAILURE(frame5->get_FrameId(&frameId)); + message += L",\"webview frame id\": " + std::to_wstring((int)frameId); + } + frame5 = wil::try_com_query(sender); + if (frame5) + { + CHECK_FAILURE(frame5->get_FrameId(&frameId)); + message += + L",\"sender webview frame id\": " + std::to_wstring((int)frameId); + } + message += + L"}" + WebViewPropertiesToJsonString(m_webviewEventSource.get()) + L"}"; + PostEventMessage(message); + return S_OK; + }) + .Get(), + &m_frameCreatedToken); + //! [FrameCreated] } } void ScenarioWebViewEventMonitor::PostEventMessage(std::wstring message) diff --git a/SampleApps/WebView2APISample/ScenarioWebViewEventMonitor.h b/SampleApps/WebView2APISample/ScenarioWebViewEventMonitor.h index d689e4d1..daf0fc8d 100644 --- a/SampleApps/WebView2APISample/ScenarioWebViewEventMonitor.h +++ b/SampleApps/WebView2APISample/ScenarioWebViewEventMonitor.h @@ -23,7 +23,7 @@ class ScenarioWebViewEventMonitor : public ComponentBase void InitializeEventView(ICoreWebView2* webviewEventView); private: - void InitializeFrameEventView(wil::com_ptr webviewFrame); + void InitializeFrameEventView(wil::com_ptr webviewFrame, int depth); // Because WebResourceRequested fires so much more often than // all other events, we default to it off and it is configurable. void EnableWebResourceRequestedEvent(bool enable); diff --git a/SampleApps/WebView2APISample/WebView2APISample.rc b/SampleApps/WebView2APISample/WebView2APISample.rc index 28aa4043..0d2804b6 100644 --- a/SampleApps/WebView2APISample/WebView2APISample.rc +++ b/SampleApps/WebView2APISample/WebView2APISample.rc @@ -87,6 +87,7 @@ BEGIN MENUITEM "Add Browser Extension", IDM_ADD_EXTENSION MENUITEM "Remove Browser Extension", IDM_REMOVE_EXTENSION MENUITEM "Enable/Disable Extension", IDM_DISABLE_EXTENSION + MENUITEM "Start Find", IDM_START_FIND END POPUP "&Window" BEGIN @@ -305,6 +306,18 @@ BEGIN MENUITEM "Throttling Control", IDM_SCENARIO_THROTTLING_CONTROL MENUITEM "Screen Capture", IDM_SCENARIO_SCREEN_CAPTURE MENUITEM "File Type Policy", IDM_SCENARIO_FILE_TYPE_POLICY + POPUP "Start Find" + BEGIN + MENUITEM "Start Find on Page Dialog", IDM_START_FIND + MENUITEM "Get Match Count", IDM_GET_MATCHES + MENUITEM "Get Active Match Index", IDM_GET_ACTIVE_MATCH_INDEX + MENUITEM "Stop Find on Page Dialog", IDM_STOP_FIND + MENUITEM "Change Find Term", IDC_FIND_TERM + MENUITEM "Toggle Highlight", IDC_SHOULD_HIGHLIGHT_ALL_MATCHES + MENUITEM "Toggle Case Sensitivity", IDC_IS_CASE_SENSITIVE + MENUITEM "Toggle Suppress Default Find Dialog", IDC_SUPPRESS_DEFAULT_FIND_DIALOG + MENUITEM "Toggle Should Match Word", IDC_SHOULD_MATCH_WHOLE_WORD + END END POPUP "&Audio" BEGIN diff --git a/SampleApps/WebView2APISample/WebView2APISample.vcxproj b/SampleApps/WebView2APISample/WebView2APISample.vcxproj index b4f233d4..7a5035d5 100644 --- a/SampleApps/WebView2APISample/WebView2APISample.vcxproj +++ b/SampleApps/WebView2APISample/WebView2APISample.vcxproj @@ -234,8 +234,10 @@ + + @@ -287,8 +289,10 @@ + + @@ -364,6 +368,9 @@ $(OutDir)\assets + + $(OutDir)\assets + $(OutDir)\assets @@ -476,6 +483,9 @@ $(OutDir)\assets + + $(OutDir)\assets + $(OutDir)\assets @@ -486,13 +496,13 @@ - + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - + diff --git a/SampleApps/WebView2APISample/assets/ScenarioDragDropOverride.html b/SampleApps/WebView2APISample/assets/ScenarioDragDropOverride.html new file mode 100644 index 00000000..383c6afc --- /dev/null +++ b/SampleApps/WebView2APISample/assets/ScenarioDragDropOverride.html @@ -0,0 +1,108 @@ + + + + + Scenario Drag Drop Override + + + + +

Scenario Drag Drop Override

+

+ This scenario demonstrates the ability to override drag drop behavior using the DragStarting Event. + Apps that handle the DragStarting event will be notified when drag is starting in the WebView2 and + can employ their own drag drop logic to override WebView2's. In the sample app, the override drag + experience will look no different from the default drag experience. By default, this webpage will use + the WebView2 default drag drop. +

+
+
+
+
+
+ + + +
+ + \ No newline at end of file diff --git a/SampleApps/WebView2APISample/packages.config b/SampleApps/WebView2APISample/packages.config index 95f96ccf..a258c35a 100644 --- a/SampleApps/WebView2APISample/packages.config +++ b/SampleApps/WebView2APISample/packages.config @@ -1,5 +1,5 @@  - + \ No newline at end of file diff --git a/SampleApps/WebView2APISample/resource.h b/SampleApps/WebView2APISample/resource.h index 9bc7ab78..a2154c39 100644 --- a/SampleApps/WebView2APISample/resource.h +++ b/SampleApps/WebView2APISample/resource.h @@ -186,7 +186,18 @@ #define IDM_SCENARIO_SAVE_AS_TOGGLE_SILENT 2040 #define IDM_SCENARIO_SAVE_AS_PROGRAMMATIC 2041 #define IDM_SCENARIO_ACCELERATOR_KEY_PRESSED 2042 +#define IDM_START_FIND 2043 +#define IDM_STOP_FIND 2044 +#define IDM_FIND_NEXT 2045 +#define IDM_FIND_PREVIOUS 2046 +#define IDM_GET_MATCHES 2047 +#define IDM_GET_ACTIVE_MATCH_INDEX 2048 #define IDM_SCENARIO_FILE_TYPE_POLICY 2049 +#define IDC_FIND_TERM 2059 +#define IDC_IS_CASE_SENSITIVE 2060 +#define IDC_SHOULD_MATCH_WHOLE_WORD 2061 +#define IDC_SHOULD_HIGHLIGHT_ALL_MATCHES 2062 +#define IDC_SUPPRESS_DEFAULT_FIND_DIALOG 2063 #define IDM_CREATION_MODE_WINDOWED 3000 #define IDM_CREATION_MODE_VISUAL_DCOMP 3001 #define IDM_CREATION_MODE_TARGET_DCOMP 3002 diff --git a/SampleApps/WebView2WindowsFormsBrowser/WebView2WindowsFormsBrowser.csproj b/SampleApps/WebView2WindowsFormsBrowser/WebView2WindowsFormsBrowser.csproj index e7dbd0c0..b2f09791 100644 --- a/SampleApps/WebView2WindowsFormsBrowser/WebView2WindowsFormsBrowser.csproj +++ b/SampleApps/WebView2WindowsFormsBrowser/WebView2WindowsFormsBrowser.csproj @@ -25,7 +25,7 @@ AnyCPU - + diff --git a/SampleApps/WebView2WpfBrowser/MainWindow.xaml b/SampleApps/WebView2WpfBrowser/MainWindow.xaml index 98a38ffc..3fbcd67f 100644 --- a/SampleApps/WebView2WpfBrowser/MainWindow.xaml +++ b/SampleApps/WebView2WpfBrowser/MainWindow.xaml @@ -107,6 +107,8 @@ found in the LICENSE file. + + diff --git a/SampleApps/WebView2WpfBrowser/MainWindow.xaml.cs b/SampleApps/WebView2WpfBrowser/MainWindow.xaml.cs index e6a86194..6746bc8e 100644 --- a/SampleApps/WebView2WpfBrowser/MainWindow.xaml.cs +++ b/SampleApps/WebView2WpfBrowser/MainWindow.xaml.cs @@ -137,6 +137,8 @@ public partial class MainWindow : Window public static RoutedCommand SharedWorkerManagerCommand = new RoutedCommand(); public static RoutedCommand GetSharedWorkersCommand = new RoutedCommand(); public static RoutedCommand ServiceWorkerSyncManagerCommand = new RoutedCommand(); + public static RoutedCommand ChildFrameEventsCommand = new RoutedCommand(); + public static RoutedCommand RemoveChildFrameEventsCommand = new RoutedCommand(); #endregion commands @@ -187,9 +189,7 @@ CoreWebView2Profile WebViewProfile // Try not to set these directly. Instead these should be updated by calling SetWebView(). // We can switch between using a WebView2 or WebView2CompositionControl element. bool _useCompositionControl = false; -#if USE_WEBVIEW2_EXPERIMENTAL WebView2CompositionControl webView2CompositionControlXamlElement = null; -#endif private FrameworkElement _webView2FrameworkElement; // Helper reference pointing to the current WV2 control. private IWebView2 _iWebView2; // Helper reference pointing to the current WV2 control. @@ -261,13 +261,11 @@ private async void MainWindow_Loaded(object sender, RoutedEventArgs e) // the _useCompositionControl value. private void SetWebView(IWebView2 newWebView2, bool useCompositionControl) { -#if USE_WEBVIEW2_EXPERIMENTAL if (useCompositionControl) { webView2CompositionControlXamlElement = newWebView2 as WebView2CompositionControl; } else -#endif { webView2XamlElement = newWebView2 as WebView2; } @@ -516,13 +514,11 @@ void AttachControlToVisualTree(UIElement control) IWebView2 CreateReplacementControl(bool useNewEnvironment, bool useCompositionControl) { IWebView2 replacementControl; -#if USE_WEBVIEW2_EXPERIMENTAL if (useCompositionControl) { replacementControl = new WebView2CompositionControl(); } else -#endif { replacementControl = new WebView2(); } @@ -3860,5 +3856,80 @@ async void ServiceWorkerSyncManagerExecuted(object target, ExecutedRoutedEventAr { await Task.Delay(0); } +#if USE_WEBVIEW2_EXPERIMENTAL + List childFrames_ = new List(); +#endif + void ChildFrameEventsExecuted(object target, ExecutedRoutedEventArgs e) + { +#if USE_WEBVIEW2_EXPERIMENTAL + _iWebView2.CoreWebView2.FrameCreated += HandleChildFrameCreated; +#endif + } + void RemoveChildFrameEventsExecuted(object target, ExecutedRoutedEventArgs e) + { +#if USE_WEBVIEW2_EXPERIMENTAL + _iWebView2.CoreWebView2.FrameCreated -= HandleChildFrameCreated; + for (int i = 0; i < childFrames_.Count; i++) + { + childFrames_[i].FrameCreated -= HandleChildFrameCreated; + childFrames_[i].NavigationStarting -= HandleChildFrameNavigationStarting; + childFrames_[i].ContentLoading -= HandleChildFrameContentLoading; + childFrames_[i].DOMContentLoaded -= HandleChildFrameDOMContentLoaded; + childFrames_[i].NavigationCompleted -= HandleChildFrameNavigationCompleted; + childFrames_[i].Destroyed -= HandleChildFrameDestroyed; + } +#endif + } + +#if USE_WEBVIEW2_EXPERIMENTAL + void HandleChildFrameCreated(object sender, CoreWebView2FrameCreatedEventArgs args) + { + CoreWebView2Frame childFrame = args.Frame; + childFrames_.Add(args.Frame); + string name = String.IsNullOrEmpty(childFrame.Name) ? "none" : childFrame.Name; + MessageBox.Show(this, "Id: " + childFrame.FrameId + " name: " + name, "Child frame created", MessageBoxButton.OK); + // + childFrame.FrameCreated += HandleChildFrameCreated; + // + childFrame.NavigationStarting += HandleChildFrameNavigationStarting; + childFrame.ContentLoading += HandleChildFrameContentLoading; + childFrame.DOMContentLoaded += HandleChildFrameDOMContentLoaded; + childFrame.NavigationCompleted += HandleChildFrameNavigationCompleted; + childFrame.Destroyed += HandleChildFrameDestroyed; + } + + void HandleChildFrameDestroyed(object sender, object args) { + var frameToRemove = childFrames_.SingleOrDefault(r => r.IsDestroyed() == 1); + if (frameToRemove != null) + { + MessageBox.Show(this, "Id: " + frameToRemove.FrameId + " FrameDestroyed", "Child frame Destroyed", MessageBoxButton.OK); + childFrames_.Remove(frameToRemove); + } + } + + void HandleChildFrameNavigationStarting(object sender, CoreWebView2NavigationStartingEventArgs args) + { + CoreWebView2Frame Frame = (CoreWebView2Frame)sender; + MessageBox.Show(this, "Id: " + Frame.FrameId + " NavigationStarting", "Child frame Navigation", MessageBoxButton.OK); + } + + void HandleChildFrameContentLoading(object sender, CoreWebView2ContentLoadingEventArgs args) + { + CoreWebView2Frame Frame = (CoreWebView2Frame)sender; + MessageBox.Show(this, "Id: " + Frame.FrameId + " ContentLoading", "Child frame Content Loading", MessageBoxButton.OK); + } + + void HandleChildFrameDOMContentLoaded(object sender, CoreWebView2DOMContentLoadedEventArgs args) + { + CoreWebView2Frame Frame = (CoreWebView2Frame)sender; + MessageBox.Show(this, "Id: " + Frame.FrameId + " DOMContentLoaded", "Child frame DOM Content Loaded", MessageBoxButton.OK); + } + + void HandleChildFrameNavigationCompleted(object sender, CoreWebView2NavigationCompletedEventArgs args) + { + CoreWebView2Frame Frame = (CoreWebView2Frame)sender; + MessageBox.Show(this, "Id: " + Frame.FrameId + " NavigationCompleted", "Child frame Navigation Completed", MessageBoxButton.OK); + } +#endif } } diff --git a/SampleApps/WebView2WpfBrowser/WebView2WpfBrowser.csproj b/SampleApps/WebView2WpfBrowser/WebView2WpfBrowser.csproj index e23a6214..7c8efeac 100644 --- a/SampleApps/WebView2WpfBrowser/WebView2WpfBrowser.csproj +++ b/SampleApps/WebView2WpfBrowser/WebView2WpfBrowser.csproj @@ -61,7 +61,7 @@ - + diff --git a/SampleApps/WebView2_WinUI3_Sample/WebView2_WinUI3_Sample/App.xaml.cs b/SampleApps/WebView2_WinUI3_Sample/WebView2_WinUI3_Sample/App.xaml.cs index e9b4de24..2a407874 100644 --- a/SampleApps/WebView2_WinUI3_Sample/WebView2_WinUI3_Sample/App.xaml.cs +++ b/SampleApps/WebView2_WinUI3_Sample/WebView2_WinUI3_Sample/App.xaml.cs @@ -22,15 +22,15 @@ public App() { this.InitializeComponent(); - // If your shipping a fixed version WebView2 SDK with your application you will need - // to use the following code (update the runtime version to what your shipping. - - //StorageFolder localFolder = Windows.ApplicationModel.Package.Current.InstalledLocation; - //String fixedPath = Path.Combine(localFolder.Path, "FixedRuntime\\95.0.1020.53"); - //Debug.WriteLine($"Launch path [{localFolder.Path}]"); - //Debug.WriteLine($"FixedRuntime path [{fixedPath}]"); - //Environment.SetEnvironmentVariable("WEBVIEW2_BROWSER_EXECUTABLE_FOLDER", fixedPath); + // If you're shipping a fixed-version WebView2 Runtime with your app, un-comment the + // following lines of code, and change the version number to the version number of the + // WebView2 Runtime that you're packaging and shipping to users: + // StorageFolder localFolder = Windows.ApplicationModel.Package.Current.InstalledLocation; + // String fixedPath = Path.Combine(localFolder.Path, "FixedRuntime\\130.0.2849.39"); + // Debug.WriteLine($"Launch path [{localFolder.Path}]"); + // Debug.WriteLine($"FixedRuntime path [{fixedPath}]"); + // Environment.SetEnvironmentVariable("WEBVIEW2_BROWSER_EXECUTABLE_FOLDER", fixedPath); } /// diff --git a/SampleApps/WebView2_WinUI3_Sample/readme.md b/SampleApps/WebView2_WinUI3_Sample/readme.md index 0566c9e7..43c37dde 100644 --- a/SampleApps/WebView2_WinUI3_Sample/readme.md +++ b/SampleApps/WebView2_WinUI3_Sample/readme.md @@ -1,50 +1,9 @@ -# Introduction -This sample shows off using a WebView2 control in a WinUi 3 Windows SDK Packaged application. - -It also optionaly shows how you would update the application to ship with a fixed WebView2 version instead of using the version installed and running on the Windows computer. - -# Relevant directories - -| Directory | Contents | ---- | --- | -| WebView2_WinUI3_Sample | Project code | -| WebView2_WinUI3_Sample (Package) | Packaging and distribution project | -| WebView2_WinUI3_Sample (Package)\FixedRuntime | (Optional) Fixed WebView2 runtime | -| WebView2_WinUI3_Sample (Package)\FixedRuntime\95.0.1020.53 | (Optional) Fixed WebView2 runtime sample | - - -# Fixed version usage -If you want to ship a fixed version of the WebView2 runtime with your application you will need to include it in your project. - -Instructions can be found at: https://learn.microsoft.com/en-us/microsoft-edge/webview2/concepts/distribution - -The following assume you are using runtime version 95.0.1020.53, you will change this number to whatever version you are using. - -You will need to: -1 Include the fixed WebView2 runtime in the package project -
\WebView2_WinUI3_Sample\WebView2_WinUI3_Sample (Package)\FixedRuntime\95.0.1020.53\
-2 Update the package project wapproj file for the version your using -
 < Content Include="FixedRuntime\95.0.1020.53\\**\*.*" > 
-3 Uncomment the code in app.xaml.cs to enable the runtime override -
-public App()
-{
-    this.InitializeComponent();
-    // If you are shipping a fixed version WebView2 SDK with your application you will need
-    // to use the following code (update the runtime version to what you are shipping.
-    StorageFolder localFolder = Windows.ApplicationModel.Package.Current.InstalledLocation;
-    String fixedPath = Path.Combine(localFolder.Path, "FixedRuntime\\95.0.1020.53");
-    Debug.WriteLine($"Launch path [{localFolder.Path}]");
-    Debug.WriteLine($"FixedRuntime path [{fixedPath}]");
-    Environment.SetEnvironmentVariable("WEBVIEW2_BROWSER_EXECUTABLE_FOLDER", fixedPath);
-}
-
-4 Update the version information for the appropriate version -
 
-String fixedPath = Path.Combine(localFolder.Path, "FixedRuntime\\95.0.1020.53");
-
- +# WinUI 3 (Windows App SDK) sample app +This sample (**WebView2_WinUI3_Sample**) demonstrates using a WebView2 control in a WinUI 3 (Windows App SDK) Packaged application. +![Sample app](./images/sample-app.png) +This sample also allows you to ship the app with a fixed-version WebView2 Runtime, instead of using whichever version of the WebView2 Runtime is installed and running on the user's computer. +To use this sample, see [WinUI 3 (Windows App SDK) sample app](https://learn.microsoft.com/microsoft-edge/webview2/samples/webview2-winui3-sample).