From 4f28fa31555af9a909d46e29b9e93ea639ac370c Mon Sep 17 00:00:00 2001 From: Jessica Chen <55165503+peiche-jessica@users.noreply.github.com> Date: Wed, 30 Aug 2023 10:45:56 -0700 Subject: [PATCH] Update projects to use latest WebView2 SDK 1.0.2065-prerelease (#206) * Updates for Win32, WPF and WinForms sample apps from 118.0.2065.0 * Updated package version for Win32, WPF and WinForms sample apps to 1.0.2065-prerelease --------- Co-authored-by: WebView2 Github Bot --- SampleApps/WebView2APISample/App.cpp | 3 +- SampleApps/WebView2APISample/AppWindow.cpp | 34 ++- SampleApps/WebView2APISample/AppWindow.h | 2 - .../WebView2APISample/ProcessComponent.cpp | 156 +++++------- .../WebView2APISample/ProcessComponent.h | 5 +- .../WebView2APISample/ScenarioSaveAs.cpp | 16 ++ SampleApps/WebView2APISample/ScenarioSaveAs.h | 10 + .../ScenarioWebViewEventMonitor.cpp | 44 +++- .../WebView2APISample/SettingsComponent.cpp | 5 +- .../WebView2APISample/SettingsComponent.h | 3 + .../WebView2APISample/ViewComponent.cpp | 9 +- SampleApps/WebView2APISample/ViewComponent.h | 1 - .../WebView2APISample.vcxproj | 28 ++- .../example-devtools-extension/devtools.html | 6 + .../example-devtools-extension/manifest.json | 9 + .../example-devtools-extension/panel.html | 7 + .../example-devtools-extension/panel.js | 1 + .../assets/sw_scope/index.html | 61 +++++ .../assets/sw_scope/simple.txt | 1 + .../WebView2APISample/assets/sw_scope/sw.js | 30 +++ SampleApps/WebView2APISample/packages.config | 2 +- SampleApps/WebView2APISample/resource.h | 1 - .../WebView2WindowsFormsBrowser.csproj | 2 +- .../WebView2WpfBrowser/Extensions.xaml.cs | 16 ++ .../WebView2WpfBrowser/MainWindow.xaml.cs | 225 +++++++++++++----- .../WebView2WpfBrowser/SaveAsDialog.xaml | 43 ++++ .../WebView2WpfBrowser/SaveAsDialog.xaml.cs | 17 ++ .../WebView2WpfBrowser.csproj | 2 +- 28 files changed, 560 insertions(+), 179 deletions(-) create mode 100644 SampleApps/WebView2APISample/ScenarioSaveAs.cpp create mode 100644 SampleApps/WebView2APISample/ScenarioSaveAs.h create mode 100644 SampleApps/WebView2APISample/assets/extensions/example-devtools-extension/devtools.html create mode 100644 SampleApps/WebView2APISample/assets/extensions/example-devtools-extension/manifest.json create mode 100644 SampleApps/WebView2APISample/assets/extensions/example-devtools-extension/panel.html create mode 100644 SampleApps/WebView2APISample/assets/extensions/example-devtools-extension/panel.js create mode 100644 SampleApps/WebView2APISample/assets/sw_scope/index.html create mode 100644 SampleApps/WebView2APISample/assets/sw_scope/simple.txt create mode 100644 SampleApps/WebView2APISample/assets/sw_scope/sw.js create mode 100644 SampleApps/WebView2WpfBrowser/SaveAsDialog.xaml create mode 100644 SampleApps/WebView2WpfBrowser/SaveAsDialog.xaml.cs diff --git a/SampleApps/WebView2APISample/App.cpp b/SampleApps/WebView2APISample/App.cpp index 2d38d407..0093733d 100644 --- a/SampleApps/WebView2APISample/App.cpp +++ b/SampleApps/WebView2APISample/App.cpp @@ -42,6 +42,7 @@ wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR lpCmdLine, int nCmd std::wstring userDataFolder(L""); std::wstring initialUri; DWORD creationModeId = IDM_CREATION_MODE_WINDOWED; + WebViewCreateOption opt; if (lpCmdLine && lpCmdLine[0]) { @@ -120,7 +121,7 @@ wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR lpCmdLine, int nCmd DpiUtil::SetProcessDpiAwarenessContext(dpiAwarenessContext); - new AppWindow(creationModeId, WebViewCreateOption(), initialUri, userDataFolder, true); + new AppWindow(creationModeId, opt, initialUri, userDataFolder, true); int retVal = RunMessagePump(); diff --git a/SampleApps/WebView2APISample/AppWindow.cpp b/SampleApps/WebView2APISample/AppWindow.cpp index 9e9803f6..4df4901f 100644 --- a/SampleApps/WebView2APISample/AppWindow.cpp +++ b/SampleApps/WebView2APISample/AppWindow.cpp @@ -1371,7 +1371,11 @@ void AppWindow::InitializeWebView() HRESULT AppWindow::OnCreateEnvironmentCompleted( HRESULT result, ICoreWebView2Environment* environment) { - CHECK_FAILURE(result); + if (result != S_OK) + { + ShowFailure(result, L"Failed to create environment object."); + return S_OK; + } m_webViewEnvironment = environment; if (m_webviewOption.entry == WebViewCreateEntry::EVER_FROM_CREATE_WITH_OPTION_MENU @@ -1569,7 +1573,6 @@ HRESULT AppWindow::OnCreateCoreWebView2ControllerCompleted( } NewComponent(this); NewComponent(this); - // We have a few of our own event handlers to register here as well RegisterEventHandlers(); @@ -1721,6 +1724,32 @@ void AppWindow::RegisterEventHandlers() args->put_Handled(FALSE); return S_OK; } + wil::com_ptr + experimental_args; + if (SUCCEEDED(args->QueryInterface(IID_PPV_ARGS(&experimental_args)))) + { + wil::com_ptr frame_info; + CHECK_FAILURE(experimental_args->get_OriginalSourceFrameInfo(&frame_info)); + wil::unique_cotaskmem_string source; + CHECK_FAILURE(frame_info->get_Source(&source)); + // The host can decide how to open based on source frame info, + // such as URI. + static const wchar_t* browser_launching_domain = L"www.example.com"; + wil::unique_bstr source_domain = GetDomainOfUri(source.get()); + const wchar_t* source_domain_as_wchar = source_domain.get(); + if (wcscmp(browser_launching_domain, source_domain_as_wchar) == 0) + { + // Open the URI in the default browser. + wil::unique_cotaskmem_string target_uri; + CHECK_FAILURE(args->get_Uri(&target_uri)); + ShellExecute( + nullptr, L"open", target_uri.get(), nullptr, nullptr, + SW_SHOWNORMAL); + CHECK_FAILURE(args->put_Handled(TRUE)); + return S_OK; + } + } + wil::com_ptr deferral; CHECK_FAILURE(args->GetDeferral(&deferral)); AppWindow* newAppWindow; @@ -2176,7 +2205,6 @@ std::wstring AppWindow::GetLocalUri( else { std::wstring path = GetLocalPath(L"assets\\" + relativePath, false); - wil::com_ptr uri; CHECK_FAILURE(CreateUri(path.c_str(), Uri_CREATE_ALLOW_IMPLICIT_FILE_SCHEME, 0, &uri)); diff --git a/SampleApps/WebView2APISample/AppWindow.h b/SampleApps/WebView2APISample/AppWindow.h index bf0445e5..ccbf488f 100644 --- a/SampleApps/WebView2APISample/AppWindow.h +++ b/SampleApps/WebView2APISample/AppWindow.h @@ -41,7 +41,6 @@ struct WebViewCreateOption WebViewCreateOption() { } - WebViewCreateOption( const std::wstring& profile_, bool inPrivate, const std::wstring& downloadPath, const std::wstring& scriptLocale_, WebViewCreateEntry entry_, bool useOSRegion_) @@ -59,7 +58,6 @@ struct WebViewCreateOption entry = opt.entry; useOSRegion = opt.useOSRegion; } - void PopupDialog(AppWindow* app); }; diff --git a/SampleApps/WebView2APISample/ProcessComponent.cpp b/SampleApps/WebView2APISample/ProcessComponent.cpp index 35d5b868..ead8ea75 100644 --- a/SampleApps/WebView2APISample/ProcessComponent.cpp +++ b/SampleApps/WebView2APISample/ProcessComponent.cpp @@ -215,63 +215,65 @@ std::wstring ProcessComponent::FrameKindToString(const COREWEBVIEW2_FRAME_KIND k } void ProcessComponent::AppendFrameInfo( - wil::com_ptr frameInfo, std::wstring& result) + wil::com_ptr frameInfo, std::wstringstream& result) { - if (!frameInfo) - { - return; - } - + UINT32 frameId = 0; + UINT32 parentFrameId = 0; + UINT32 mainFrameId = 0; + UINT32 firstLevelFrameId = 0; + std::wstring type = L"other child frame"; wil::unique_cotaskmem_string nameRaw; + wil::unique_cotaskmem_string sourceRaw; + COREWEBVIEW2_FRAME_KIND frameKind = COREWEBVIEW2_FRAME_KIND_OTHER; + CHECK_FAILURE(frameInfo->get_Name(&nameRaw)); - result.append(L"{frame name:"); - result.append(nameRaw.get()); + std::wstring name = ((std::wstring)(nameRaw.get())).empty() ? L"none" : nameRaw.get(); + CHECK_FAILURE(frameInfo->get_Source(&sourceRaw)); + std::wstring source = ((std::wstring)(sourceRaw.get())).empty() ? L"none" : sourceRaw.get(); wil::com_ptr frameInfoExperimental; CHECK_FAILURE(frameInfo->QueryInterface(IID_PPV_ARGS(&frameInfoExperimental))); - UINT32 frameId = 0; frameInfoExperimental->get_FrameId(&frameId); - result.append(L" | frame Id:" + std::to_wstring(frameId)); + frameInfoExperimental->get_FrameKind(&frameKind); + + wil::com_ptr parentFrameInfo; + CHECK_FAILURE(frameInfoExperimental->get_ParentFrameInfo(&parentFrameInfo)); + if (parentFrameInfo) + { + CHECK_FAILURE(parentFrameInfo->QueryInterface(IID_PPV_ARGS(&frameInfoExperimental))); + CHECK_FAILURE(frameInfoExperimental->get_FrameId(&parentFrameId)); + } - BOOL isMainFrameOrFirstLevelframeInfo = false; wil::com_ptr mainFrameInfo = GetAncestorMainFrameInfo(frameInfo); - wil::com_ptr firstLevelFrameInfo = - GetAncestorFirstLevelFrameInfo(frameInfo); - // check if a frame is a main frame. if (mainFrameInfo == frameInfo) { - result.append(L" | frame type: main frame"); - isMainFrameOrFirstLevelframeInfo = true; + type = L"main frame"; } - // check if a frame is a first level frame. + CHECK_FAILURE(mainFrameInfo->QueryInterface(IID_PPV_ARGS(&frameInfoExperimental))); + CHECK_FAILURE(frameInfoExperimental->get_FrameId(&mainFrameId)); + + wil::com_ptr firstLevelFrameInfo = + GetAncestorFirstLevelFrameInfo(frameInfo); if (firstLevelFrameInfo == frameInfo) { - result.append(L" | frame type: first level frame"); - isMainFrameOrFirstLevelframeInfo = true; - } - if (!isMainFrameOrFirstLevelframeInfo) - { - result.append(L" | frame type: other child frame"); + type = L"first level frame"; } - - COREWEBVIEW2_FRAME_KIND frameKind = COREWEBVIEW2_FRAME_KIND_OTHER; - frameInfoExperimental->get_FrameKind(&frameKind); - result.append(L"\n | frame kind:" + FrameKindToString(frameKind)); - - wil::com_ptr parentFrameInfo; - CHECK_FAILURE(frameInfoExperimental->get_ParentFrameInfo(&parentFrameInfo)); - if (parentFrameInfo) + if (firstLevelFrameInfo) { - CHECK_FAILURE(parentFrameInfo->QueryInterface(IID_PPV_ARGS(&frameInfoExperimental))); - CHECK_FAILURE(frameInfoExperimental->get_FrameId(&frameId)); - result.append(L" | parent frame Id:" + std::to_wstring(frameId)); + CHECK_FAILURE( + firstLevelFrameInfo->QueryInterface(IID_PPV_ARGS(&frameInfoExperimental))); + CHECK_FAILURE(frameInfoExperimental->get_FrameId(&firstLevelFrameId)); } - wil::unique_cotaskmem_string sourceRaw; - CHECK_FAILURE(frameInfo->get_Source(&sourceRaw)); - result.append(L"\n | frame source:\n\""); - result.append(sourceRaw.get()); - result.append(L"\""); + result << L"{frame name:" << name << L" | frame Id:" << std::to_wstring(frameId) + << L" | parent frame Id:" + << ((parentFrameId == 0) ? L"none" : std::to_wstring(parentFrameId)) + << L" | frame type:" << type << L"\n" + << L" | ancestor main frame Id:" << std::to_wstring(mainFrameId) + << L" | ancestor first level frame Id:" + << ((firstLevelFrameId == 0) ? L"none" : std::to_wstring(firstLevelFrameId)) << L"\n" + << L" | frame kind:" << FrameKindToString(frameKind) << L"\n" + << L" | frame source:" << source << L"}," << std::endl; } // Get the ancestor main frameInfo. @@ -308,36 +310,6 @@ wil::com_ptr ProcessComponent::GetAncestorFirstLevelFram return firstLevelFrameInfo; } -// Append the frame Id of the ancestor first level frame and ancestor main frame. -void ProcessComponent::AppendAncestorFrameInfo( - wil::com_ptr frameInfo, std::wstring& result) -{ - if (!frameInfo) - { - return; - } - - wil::com_ptr mainFrameInfo = GetAncestorMainFrameInfo(frameInfo); - wil::com_ptr firstLevelFrameInfo = - GetAncestorFirstLevelFrameInfo(frameInfo); - wil::com_ptr frameInfoExperimental; - UINT32 frameId = 0; - if (firstLevelFrameInfo) - { - CHECK_FAILURE( - firstLevelFrameInfo->QueryInterface(IID_PPV_ARGS(&frameInfoExperimental))); - CHECK_FAILURE(frameInfoExperimental->get_FrameId(&frameId)); - result.append(L"\n | ancestor first level frame Id:" + std::to_wstring(frameId)); - } - if (mainFrameInfo) - { - CHECK_FAILURE(mainFrameInfo->QueryInterface(IID_PPV_ARGS(&frameInfoExperimental))); - CHECK_FAILURE(frameInfoExperimental->get_FrameId(&frameId)); - result.append(L"\n | ancestor main frame Id:" + std::to_wstring(frameId)); - } - result.append(L"},\n"); -} - void ProcessComponent::ShowProcessFrameInfo() { auto environmentExperimental11 = @@ -353,8 +325,8 @@ void ProcessComponent::ShowProcessFrameInfo() UINT32 processCount = 0; UINT32 rendererProcessCount = 0; CHECK_FAILURE(processCollection->get_Count(&processCount)); - std::wstring result; - std::wstring otherProcessResult; + std::wstringstream otherProcessInfos; + std::wstringstream rendererProcessInfos; for (UINT32 i = 0; i < processCount; i++) { Microsoft::WRL::ComPtr processInfo; @@ -366,7 +338,7 @@ void ProcessComponent::ShowProcessFrameInfo() if (kind == COREWEBVIEW2_PROCESS_KIND_RENDERER) { //! [AssociatedFrameInfos] - std::wstring rendererProcessResult; + std::wstringstream rendererProcess; wil::com_ptr processInfoExperimental; CHECK_FAILURE(processInfo->QueryInterface( @@ -384,39 +356,37 @@ void ProcessComponent::ShowProcessFrameInfo() wil::com_ptr frameInfo; CHECK_FAILURE(iterator->GetCurrent(&frameInfo)); - AppendFrameInfo(frameInfo, rendererProcessResult); - AppendAncestorFrameInfo(frameInfo, rendererProcessResult); + AppendFrameInfo(frameInfo, rendererProcess); BOOL hasNext = FALSE; CHECK_FAILURE(iterator->MoveNext(&hasNext)); frameInfoCount++; } - rendererProcessResult.insert( - 0, std::to_wstring(frameInfoCount) + - L" frameInfo(s) found in Renderer Process ID:" + - std::to_wstring(processId) + L"\n"); - result.append(rendererProcessResult + L"\n"); + rendererProcessInfos + << std::to_wstring(frameInfoCount) + << L" frameInfo(s) found in Renderer Process ID:" + << std::to_wstring(processId) << L"\n" + << rendererProcess.str() << std::endl; //! [AssociatedFrameInfos] rendererProcessCount++; } else { - otherProcessResult.append( - L"Process Id:" + std::to_wstring(processId) + - L" | Process Kind:" + ProcessKindToString(kind) + L"\n"); + otherProcessInfos << L"Process Id:" << std::to_wstring(processId) + << L" | Process Kind:" + << ProcessKindToString(kind) << std::endl; } } - result.insert( - 0, std::to_wstring(processCount) + L" process(es) found, from which " + - std::to_wstring(rendererProcessCount) + - L" renderer process(es) found\n\n"); - otherProcessResult.insert( - 0, L"\nRemaining " + - std::to_wstring(processCount - rendererProcessCount) + - L" Process(es) Infos:\n"); - result.append(otherProcessResult); - MessageBox( - nullptr, result.c_str(), L"Process Info with Associated Frames", MB_OK); + std::wstringstream message; + message << std::to_wstring(processCount) + << L" process(es) found, from which " + << std::to_wstring(rendererProcessCount) + << L" renderer process(es) found\n\n" + << rendererProcessInfos.str() << L"Remaining Process(es) Infos:\n" + << otherProcessInfos.str(); + + m_appWindow->AsyncMessageBox( + std::move(message.str()), L"Process Info with Associated Frames"); return S_OK; }) .Get())); diff --git a/SampleApps/WebView2APISample/ProcessComponent.h b/SampleApps/WebView2APISample/ProcessComponent.h index d0520706..693ad628 100644 --- a/SampleApps/WebView2APISample/ProcessComponent.h +++ b/SampleApps/WebView2APISample/ProcessComponent.h @@ -53,9 +53,8 @@ class ProcessComponent : public ComponentBase wil::com_ptr m_processCollection; EventRegistrationToken m_processFailedToken = {}; EventRegistrationToken m_processInfosChangedToken = {}; - void AppendAncestorFrameInfo( - wil::com_ptr frameInfo, std::wstring& result); - void AppendFrameInfo(wil::com_ptr frameInfo, std::wstring& result); + void AppendFrameInfo( + wil::com_ptr frameInfo, std::wstringstream& result); wil::com_ptr GetAncestorFirstLevelFrameInfo( wil::com_ptr frameInfo); wil::com_ptr GetAncestorMainFrameInfo( diff --git a/SampleApps/WebView2APISample/ScenarioSaveAs.cpp b/SampleApps/WebView2APISample/ScenarioSaveAs.cpp new file mode 100644 index 00000000..1634dff9 --- /dev/null +++ b/SampleApps/WebView2APISample/ScenarioSaveAs.cpp @@ -0,0 +1,16 @@ +// 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 "ScenarioSaveAs.h" + +#include "App.h" +#include "AppWindow.h" +#include "CheckFailure.h" +#include "Shlwapi.h" +#include "TextInputDialog.h" +#include "resource.h" + +using namespace Microsoft::WRL; diff --git a/SampleApps/WebView2APISample/ScenarioSaveAs.h b/SampleApps/WebView2APISample/ScenarioSaveAs.h new file mode 100644 index 00000000..ff55b686 --- /dev/null +++ b/SampleApps/WebView2APISample/ScenarioSaveAs.h @@ -0,0 +1,10 @@ +// 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 + +#include "AppWindow.h" +#include "ComponentBase.h" diff --git a/SampleApps/WebView2APISample/ScenarioWebViewEventMonitor.cpp b/SampleApps/WebView2APISample/ScenarioWebViewEventMonitor.cpp index 6034cc0e..310e1a44 100644 --- a/SampleApps/WebView2APISample/ScenarioWebViewEventMonitor.cpp +++ b/SampleApps/WebView2APISample/ScenarioWebViewEventMonitor.cpp @@ -656,16 +656,44 @@ void ScenarioWebViewEventMonitor::InitializeEventView(ICoreWebView2* webviewEven encodedName = EncodeQuote(name.get()); } + wil::com_ptr + experimental_args; + std::wstring frameName = EncodeQuote(L""); + std::wstring frameUri = EncodeQuote(L""); + if (SUCCEEDED(args->QueryInterface(IID_PPV_ARGS(&experimental_args)))) + { + wil::com_ptr frame_info; + CHECK_FAILURE(experimental_args->get_OriginalSourceFrameInfo(&frame_info)); + wil::unique_cotaskmem_string name; + CHECK_FAILURE(frame_info->get_Name(&name)); + frameName = EncodeQuote(name.get()); + wil::unique_cotaskmem_string source; + CHECK_FAILURE(frame_info->get_Source(&source)); + frameUri = EncodeQuote(source.get()); + } + std::wstring message = L"{ \"kind\": \"event\", \"name\": \"NewWindowRequested\", \"args\": {" - L"\"handled\": " + BoolToString(handled) + L", " - L"\"isUserInitiated\": " + BoolToString(isUserInitiated) + L", " - L"\"uri\": " + EncodeQuote(uri.get()) + L", " - L"\"name\": " + encodedName + L", " - L"\"newWindow\": null" - L"}" - + WebViewPropertiesToJsonString(m_webviewEventSource.get()) - + L"}"; + L"\"handled\": " + + BoolToString(handled) + + L", " + L"\"isUserInitiated\": " + + BoolToString(isUserInitiated) + + L", " + L"\"uri\": " + + EncodeQuote(uri.get()) + + L", " + L"\"name\": " + + encodedName + + L", " + L"\"newWindow\": null" + + L", " + L"\"frameName\": " + + frameName + + L", " + L"\"frameUri\": " + + frameUri + L"}" + + WebViewPropertiesToJsonString(m_webviewEventSource.get()) + L"}"; PostEventMessage(message); return S_OK; diff --git a/SampleApps/WebView2APISample/SettingsComponent.cpp b/SampleApps/WebView2APISample/SettingsComponent.cpp index 68fdcaab..919effb0 100644 --- a/SampleApps/WebView2APISample/SettingsComponent.cpp +++ b/SampleApps/WebView2APISample/SettingsComponent.cpp @@ -16,9 +16,6 @@ using namespace Microsoft::WRL; -// Some utility functions -static wil::unique_bstr GetDomainOfUri(PWSTR uri); - SettingsComponent::SettingsComponent( AppWindow* appWindow, ICoreWebView2Environment* environment, SettingsComponent* old) : m_appWindow(appWindow), m_webViewEnvironment(environment), @@ -1766,7 +1763,7 @@ SettingsComponent::~SettingsComponent() m_webView->remove_PermissionRequested(m_permissionRequestedToken); } // Take advantage of urlmon's URI library to parse a URI -static wil::unique_bstr GetDomainOfUri(PWSTR uri) +wil::unique_bstr GetDomainOfUri(PWSTR uri) { wil::com_ptr uriObject; CreateUri(uri, Uri_CREATE_CANONICALIZE | Uri_CREATE_NO_DECODE_EXTRA_INFO, 0, &uriObject); diff --git a/SampleApps/WebView2APISample/SettingsComponent.h b/SampleApps/WebView2APISample/SettingsComponent.h index a04c8392..0dbae70e 100644 --- a/SampleApps/WebView2APISample/SettingsComponent.h +++ b/SampleApps/WebView2APISample/SettingsComponent.h @@ -14,6 +14,9 @@ #include "ComponentBase.h" #include "CustomStatusBar.h" +// Some utility functions +wil::unique_bstr GetDomainOfUri(PWSTR uri); + // This component handles commands from the Settings menu. It also handles the // NavigationStarting, FrameNavigationStarting, WebResourceRequested, ScriptDialogOpening, // and PermissionRequested events. diff --git a/SampleApps/WebView2APISample/ViewComponent.cpp b/SampleApps/WebView2APISample/ViewComponent.cpp index 22c2d4e9..901367c4 100644 --- a/SampleApps/WebView2APISample/ViewComponent.cpp +++ b/SampleApps/WebView2APISample/ViewComponent.cpp @@ -173,7 +173,6 @@ ViewComponent::ViewComponent( } //! [SystemCursorId] } - if (SUCCEEDED(hr)) { SetClassLongPtr( @@ -357,7 +356,8 @@ bool ViewComponent::HandleWindowMessage( } } //! [ToggleIsVisibleOnMinimize] - if ((message >= WM_MOUSEFIRST && message <= WM_MOUSELAST) || message == WM_MOUSELEAVE) + if ((message >= WM_MOUSEFIRST && message <= WM_MOUSELAST) + || message == WM_MOUSELEAVE) { return OnMouseMessage(message, wParam, lParam); } @@ -377,7 +377,6 @@ bool ViewComponent::HandleWindowMessage( //! [NotifyParentWindowPositionChanged] return false; } - //! [SetPreferredColorScheme] void ViewComponent::SetPreferredColorScheme(COREWEBVIEW2_PREFERRED_COLOR_SCHEME value) { @@ -707,7 +706,9 @@ bool ViewComponent::OnMouseMessage(UINT message, WPARAM wParam, LPARAM lParam) { POINT point; POINTSTOPOINT(point, lParam); - if (message == WM_MOUSEWHEEL || message == WM_MOUSEHWHEEL) + if (message == WM_MOUSEWHEEL || + message == WM_MOUSEHWHEEL + ) { // Mouse wheel messages are delivered in screen coordinates. // SendMouseInput expects client coordinates for the WebView, so convert diff --git a/SampleApps/WebView2APISample/ViewComponent.h b/SampleApps/WebView2APISample/ViewComponent.h index b2536fe8..08945122 100644 --- a/SampleApps/WebView2APISample/ViewComponent.h +++ b/SampleApps/WebView2APISample/ViewComponent.h @@ -111,7 +111,6 @@ class ViewComponent : public ComponentBase bool m_isCapturingMouse = false; std::unordered_set m_pointerIdsStartingInWebView; D2D1_MATRIX_4X4_F m_webViewTransformMatrix = D2D1::Matrix4x4F(); - void BuildDCompTreeUsingVisual(); void DestroyDCompVisualTree(); diff --git a/SampleApps/WebView2APISample/WebView2APISample.vcxproj b/SampleApps/WebView2APISample/WebView2APISample.vcxproj index a1aeb61a..c33dda3b 100644 --- a/SampleApps/WebView2APISample/WebView2APISample.vcxproj +++ b/SampleApps/WebView2APISample/WebView2APISample.vcxproj @@ -234,6 +234,7 @@ + @@ -280,6 +281,7 @@ + @@ -306,7 +308,6 @@ - @@ -317,6 +318,18 @@ $(OutDir)\assets + + $(OutDir)\assets + + + $(OutDir)\assets + + + $(OutDir)\assets + + + $(OutDir)\assets + $(OutDir)\assets @@ -344,6 +357,15 @@ $(OutDir)\assets + + $(OutDir)\assets + + + $(OutDir)\assets + + + $(OutDir)\assets + $(OutDir)\assets @@ -394,13 +416,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/extensions/example-devtools-extension/devtools.html b/SampleApps/WebView2APISample/assets/extensions/example-devtools-extension/devtools.html new file mode 100644 index 00000000..e9b52a7f --- /dev/null +++ b/SampleApps/WebView2APISample/assets/extensions/example-devtools-extension/devtools.html @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/SampleApps/WebView2APISample/assets/extensions/example-devtools-extension/manifest.json b/SampleApps/WebView2APISample/assets/extensions/example-devtools-extension/manifest.json new file mode 100644 index 00000000..bfca89dc --- /dev/null +++ b/SampleApps/WebView2APISample/assets/extensions/example-devtools-extension/manifest.json @@ -0,0 +1,9 @@ +{ + "manifest_version": 2, + "name": "Example Developer Tools", + "version": "0.1", + "key": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArRkuE54mFLpFQWdzxe4KM9HeO4RqaoQPyi2cq1bfEVC0KkK6pRJhzRF5HtJ6i9QB/oZz2DJB+b4PfLbebJJPq9CmFc9UyEWVj7+WtdHVi+hvK9Iihyfnha3HhXIAH75WSo99u+Y1Zjo+XcoeLbDr93t/wZ6TePAzCosOJ4uzKqtzV+O5J6RaquutqOaN5Qm0tcvfRmqPxprGI1IeIIuS1UZvEsYbgHJ8uj1h3SfC3tHvi8qPpzW6ktgtrdrUtNLMnPg5Mu8WkV/9M/0y+mA3RBRnXeUo8l1uxXRCvpPQX8554SaCmg9Foow0jcXiv+1Lzv+Rwq4AT+Fb8hUeDPB/PQIDAQAB", + "description": "Example developer tools extension", + "devtools_page": "devtools.html", + "minimum_chrome_version": "10.0" +} \ No newline at end of file diff --git a/SampleApps/WebView2APISample/assets/extensions/example-devtools-extension/panel.html b/SampleApps/WebView2APISample/assets/extensions/example-devtools-extension/panel.html new file mode 100644 index 00000000..8ab46361 --- /dev/null +++ b/SampleApps/WebView2APISample/assets/extensions/example-devtools-extension/panel.html @@ -0,0 +1,7 @@ + + + + +

This is an example devtools extension

+ + \ No newline at end of file diff --git a/SampleApps/WebView2APISample/assets/extensions/example-devtools-extension/panel.js b/SampleApps/WebView2APISample/assets/extensions/example-devtools-extension/panel.js new file mode 100644 index 00000000..0a6304e8 --- /dev/null +++ b/SampleApps/WebView2APISample/assets/extensions/example-devtools-extension/panel.js @@ -0,0 +1 @@ +chrome.devtools.panels.create('Example', null, 'panel.html', null); \ No newline at end of file diff --git a/SampleApps/WebView2APISample/assets/sw_scope/index.html b/SampleApps/WebView2APISample/assets/sw_scope/index.html new file mode 100644 index 00000000..b3580d09 --- /dev/null +++ b/SampleApps/WebView2APISample/assets/sw_scope/index.html @@ -0,0 +1,61 @@ + + + + VirtualHostMappingForServiceWorker + + + +

Start to register sw.js

+ +

Fetch via virtual host

+

Click the fetch button to get "./txt_from_local_asset", which will be fulfilled by SW + fetching a kServiceWorkerSubResource via virtual host mapping.

+

+ + +

Fetch from service worker cache

+

Click the fetch button to get "./image_from_cache", the image cached previously by SW's install handler + will be served.

+

+
+ +

Fetch from network

+

Click the fetch button to get an image from external network, without involving cache and virtual host mapping.

+

+
+ + diff --git a/SampleApps/WebView2APISample/assets/sw_scope/simple.txt b/SampleApps/WebView2APISample/assets/sw_scope/simple.txt new file mode 100644 index 00000000..e49c48e4 --- /dev/null +++ b/SampleApps/WebView2APISample/assets/sw_scope/simple.txt @@ -0,0 +1 @@ +Simple text file under assets\sw_scope \ No newline at end of file diff --git a/SampleApps/WebView2APISample/assets/sw_scope/sw.js b/SampleApps/WebView2APISample/assets/sw_scope/sw.js new file mode 100644 index 00000000..8df6d32f --- /dev/null +++ b/SampleApps/WebView2APISample/assets/sw_scope/sw.js @@ -0,0 +1,30 @@ +'use strict'; + +const CACHE_NAME = 'sw_cache'; +const CACHE_LIST = [ + 'cached_by_sw_install.jpg' +]; + +self.addEventListener('install', event => { + console.log('sw_scope/sw.js handles install event'); + event.waitUntil(caches.open(CACHE_NAME) + .then(cache => cache.addAll(CACHE_LIST)) + .then(self.skipWaiting()) + ); +}); + +self.addEventListener('activate', event => { + console.log('sw_scope/sw.js handles activate event'); + event.waitUntil(clients.claim()); +}); + +self.addEventListener('fetch', event => { + console.log('sw_scope/sw.js handles fetch event for', event.request.url); + if (event.request.url.indexOf('txt_from_local_asset') != -1) { + event.respondWith(fetch('./simple.txt')); + } else if (event.request.url.indexOf('image_from_cache') != -1) { + event.respondWith(caches.match('./cached_by_sw_install.jpg')); + } else { + event.respondWith(fetch(event.request)); + } +}); \ No newline at end of file diff --git a/SampleApps/WebView2APISample/packages.config b/SampleApps/WebView2APISample/packages.config index 6d1c7787..d5070d83 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 20c83bd7..ca825748 100644 --- a/SampleApps/WebView2APISample/resource.h +++ b/SampleApps/WebView2APISample/resource.h @@ -176,7 +176,6 @@ #define IDM_PERMISSION_MANAGEMENT 2036 #define IDM_SCENARIO_CLEAR_CUSTOM_DATA_PARTITION 2037 #define IDM_SCENARIO_NOTIFICATION 2039 - #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 a44c1f05..6a8ffa51 100644 --- a/SampleApps/WebView2WindowsFormsBrowser/WebView2WindowsFormsBrowser.csproj +++ b/SampleApps/WebView2WindowsFormsBrowser/WebView2WindowsFormsBrowser.csproj @@ -25,7 +25,7 @@ AnyCPU - + diff --git a/SampleApps/WebView2WpfBrowser/Extensions.xaml.cs b/SampleApps/WebView2WpfBrowser/Extensions.xaml.cs index dd0a8df0..0aedd53a 100644 --- a/SampleApps/WebView2WpfBrowser/Extensions.xaml.cs +++ b/SampleApps/WebView2WpfBrowser/Extensions.xaml.cs @@ -24,7 +24,9 @@ public Extensions(CoreWebView2 coreWebView2) { m_coreWebView2 = coreWebView2; InitializeComponent(); +#if USE_WEBVIEW2_EXPERIMENTAL _ = FillViewAsync(); +#endif } public class ListEntry @@ -41,6 +43,7 @@ public override string ToString() List m_listData = new List(); +#if USE_WEBVIEW2_EXPERIMENTAL private async System.Threading.Tasks.Task FillViewAsync() { IReadOnlyList extensionsList = await m_coreWebView2.Profile.GetBrowserExtensionsAsync(); @@ -57,6 +60,7 @@ private async System.Threading.Tasks.Task FillViewAsync() ExtensionsList.ItemsSource = m_listData; ExtensionsList.Items.Refresh(); } +#endif private void ExtensionsToggleEnabled(object sender, RoutedEventArgs e) { @@ -65,6 +69,7 @@ private void ExtensionsToggleEnabled(object sender, RoutedEventArgs e) private async System.Threading.Tasks.Task ExtensionsToggleEnabledAsync(object sender, RoutedEventArgs e) { +#if USE_WEBVIEW2_EXPERIMENTAL ListEntry entry = (ListEntry)ExtensionsList.SelectedItem; IReadOnlyList extensionsList = await m_coreWebView2.Profile.GetBrowserExtensionsAsync(); bool found = false; @@ -89,6 +94,9 @@ private async System.Threading.Tasks.Task ExtensionsToggleEnabledAsync(object se MessageBox.Show("Failed to find extension"); } await FillViewAsync(); +#else + await Task.CompletedTask; +#endif } private void ExtensionsAdd(object sender, RoutedEventArgs e) @@ -98,6 +106,7 @@ private void ExtensionsAdd(object sender, RoutedEventArgs e) private async System.Threading.Tasks.Task ExtensionsAddAsync(object sender, RoutedEventArgs e) { +#if USE_WEBVIEW2_EXPERIMENTAL var dialog = new TextInputDialog( title: "Add extension", description: "Enter the absolute Windows file path to the unpackaged browser extension", @@ -115,6 +124,9 @@ private async System.Threading.Tasks.Task ExtensionsAddAsync(object sender, Rout MessageBox.Show("Failed to add extension: " + exception); } } +#else + await Task.CompletedTask; +#endif } private void ExtensionsRemove(object sender, RoutedEventArgs e) @@ -124,6 +136,7 @@ private void ExtensionsRemove(object sender, RoutedEventArgs e) private async System.Threading.Tasks.Task ExtensionsRemoveAsync(object sender, RoutedEventArgs e) { +#if USE_WEBVIEW2_EXPERIMENTAL ListEntry entry = (ListEntry)ExtensionsList.SelectedItem; if (MessageBox.Show("Remove extension " + entry + "?", "Confirm removal", MessageBoxButton.OKCancel) == MessageBoxResult.OK) { @@ -151,6 +164,9 @@ private async System.Threading.Tasks.Task ExtensionsRemoveAsync(object sender, R } } await FillViewAsync(); +#else + await Task.CompletedTask; +#endif } } } diff --git a/SampleApps/WebView2WpfBrowser/MainWindow.xaml.cs b/SampleApps/WebView2WpfBrowser/MainWindow.xaml.cs index 9286f9c6..4c54403c 100644 --- a/SampleApps/WebView2WpfBrowser/MainWindow.xaml.cs +++ b/SampleApps/WebView2WpfBrowser/MainWindow.xaml.cs @@ -1,4 +1,4 @@ -// Copyright (C) Microsoft Corporation. All rights reserved. +// 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. @@ -66,6 +66,9 @@ public partial class MainWindow : Window public static RoutedCommand GeneralAutofillCommand = new RoutedCommand(); public static RoutedCommand PinchZoomCommand = new RoutedCommand(); public static RoutedCommand SwipeNavigationCommand = new RoutedCommand(); + public static RoutedCommand DeleteProfileCommand = new RoutedCommand(); + public static RoutedCommand NonClientRegionSupportCommand = new RoutedCommand(); + public static RoutedCommand NonClientRegionSupportEnabledCommand = new RoutedCommand(); public static RoutedCommand ToggleMuteStateCommand = new RoutedCommand(); public static RoutedCommand AllowExternalDropCommand = new RoutedCommand(); public static RoutedCommand LaunchingExternalUriSchemeCommand = new RoutedCommand(); @@ -118,6 +121,10 @@ public partial class MainWindow : Window public static RoutedCommand ClearCustomDataPartitionCommand = new RoutedCommand(); public static RoutedCommand ProcessFrameInfoCommand = new RoutedCommand(); + public static RoutedCommand OpenSaveAsDialogCommand = new RoutedCommand(); + public static RoutedCommand SaveAsSilentCommand = new RoutedCommand(); + + bool _isNavigating = false; // for add/remove initialize script @@ -162,6 +169,7 @@ CoreWebView2Profile WebViewProfile } } + bool _isNewWindowRequest = false; List _webViewFrames = new List(); IReadOnlyList _processList = new List(); @@ -196,20 +204,31 @@ CoreWebView2Profile WebViewProfile public MainWindow() { DataContext = this; + Loaded += MainWindow_Loaded; InitializeComponent(); - AttachControlEventHandlers(webView); - // Set background transparent - webView.DefaultBackgroundColor = System.Drawing.Color.Transparent; } - public MainWindow(CoreWebView2CreationProperties creationProperties = null) + public MainWindow( + CoreWebView2CreationProperties creationProperties = null, + bool isNewWindowRequest = false) { this.CreationProperties = creationProperties; DataContext = this; + Loaded += MainWindow_Loaded; + _isNewWindowRequest = isNewWindowRequest; InitializeComponent(); + } + + private async void MainWindow_Loaded(object sender, RoutedEventArgs e) + { + await InitializeWebView(); + } + + async System.Threading.Tasks.Task InitializeWebView() { AttachControlEventHandlers(webView); // Set background transparent webView.DefaultBackgroundColor = System.Drawing.Color.Transparent; + await webView.EnsureCoreWebView2Async(); } void AttachControlEventHandlers(WebView2 control) @@ -871,6 +890,7 @@ void SetUserAgentCmdExecuted(object target, ExecutedRoutedEventArgs e) void SetCustomDataPartitionCmdExecuted(object target, ExecutedRoutedEventArgs e) { +#if USE_WEBVIEW2_EXPERIMENTAL // var dialog = new TextInputDialog( title: "Custom Data Partition", @@ -881,10 +901,12 @@ void SetCustomDataPartitionCmdExecuted(object target, ExecutedRoutedEventArgs e) webView.CoreWebView2.CustomDataPartitionId = dialog.Input.Text; } // +#endif } async void ClearCustomDataPartitionCmdExecuted(object target, ExecutedRoutedEventArgs e) { +#if USE_WEBVIEW2_EXPERIMENTAL // var dialog = new TextInputDialog( title: "Clear Custom Data Partition", @@ -905,6 +927,9 @@ async void ClearCustomDataPartitionCmdExecuted(object target, ExecutedRoutedEven } } // +#else + await Task.CompletedTask; +#endif } void WebMessagesCmdExecuted(object target, ExecutedRoutedEventArgs e) @@ -1256,6 +1281,21 @@ void SwipeNavigationCmdExecuted(object target, ExecutedRoutedEventArgs e) } } + void DeleteProfileExecuted(object target, ExecutedRoutedEventArgs e) + { + } + void NonClientRegionSupportCmdExecuted(object target, ExecutedRoutedEventArgs e) + { + } + void NonClientRegionSupportEnabledCmdExecuted(object target, ExecutedRoutedEventArgs e) + { + } + void WebView_DOMContentLoadedNonClientRegionSupport(object sender, CoreWebView2DOMContentLoadedEventArgs e) + { + } + void WebView_NavigationStartingNonClientRegionSupport(object sender, CoreWebView2NavigationStartingEventArgs e) + { + } void PdfToolbarSaveCmdExecuted(object target, ExecutedRoutedEventArgs e) { // @@ -1783,6 +1823,7 @@ void ResumeCmdExecuted(object target, ExecutedRoutedEventArgs e) async void CheckUpdateCmdExecuted(object target, ExecutedRoutedEventArgs e) { +#if USE_WEBVIEW2_EXPERIMENTAL try { // @@ -1795,6 +1836,9 @@ async void CheckUpdateCmdExecuted(object target, ExecutedRoutedEventArgs e) { MessageBox.Show(this, "UpdateRuntimeAsync failed:" + exception.Message, "UpdateRuntimeAsync"); } +#else + await Task.CompletedTask; +#endif } bool _allowWebViewShortcutKeys = true; @@ -1927,14 +1971,20 @@ private string GetStartPageUri(CoreWebView2 webView2) return newUri; } +#if USE_WEBVIEW2_EXPERIMENTAL + Action OnWebViewFirstInitialized; +#endif void WebView_CoreWebView2InitializationCompleted(object sender, CoreWebView2InitializationCompletedEventArgs e) { if (e.IsSuccess) { // Setup host resource mapping for local files webView.CoreWebView2.SetVirtualHostNameToFolderMapping("appassets.example", "assets", CoreWebView2HostResourceAccessKind.DenyCors); - // Set StartPage Uri - webView.Source = new Uri(GetStartPageUri(webView.CoreWebView2)); + // Set StartPage Uri, unless this WebView will be used for a new window request + if (!_isNewWindowRequest) + { + webView.Source = new Uri(GetStartPageUri(webView.CoreWebView2)); + } // webView.CoreWebView2.ProcessFailed += WebView_ProcessFailed; @@ -1953,9 +2003,7 @@ void WebView_CoreWebView2InitializationCompleted(object sender, CoreWebView2Init // webView.CoreWebView2.DOMContentLoaded += WebView_PermissionManager_DOMContentLoaded; webView.CoreWebView2.WebMessageReceived += WebView_PermissionManager_WebMessageReceived; - // - webView.CoreWebView2.NotificationReceived += WebView_NotificationReceived; - // + // The CoreWebView2Environment instance is reused when re-assigning CoreWebView2CreationProperties // to the replacement control. We don't need to re-attach the event handlers unless the environment // instance has changed. @@ -1983,7 +2031,45 @@ void WebView_CoreWebView2InitializationCompleted(object sender, CoreWebView2Init webView.CoreWebView2.FrameCreated += WebView_HandleIFrames; SetDefaultDownloadDialogPosition(); - WebViewProfile.Deleted += WebViewProfile_Deleted; +#if USE_WEBVIEW2_EXPERIMENTAL + OnWebViewFirstInitialized?.Invoke(); + + webView.CoreWebView2.NewWindowRequested += delegate ( + object webview2, CoreWebView2NewWindowRequestedEventArgs args) + { + // The host can decide how to open based on source frame info, + // such as URI. + string sampleUri = "https://www.example.com/"; + bool useDefaultBrowser = + (args.OriginalSourceFrameInfo.Source == sampleUri); + if (useDefaultBrowser) + { + ProcessStartInfo startInfo = new ProcessStartInfo + { + FileName = args.Uri, + // Open the URI in the default browser. + UseShellExecute = true + }; + Process.Start(startInfo); + args.Handled = true; + } + else + { + CoreWebView2Deferral deferral = args.GetDeferral(); + MainWindow main_window = new MainWindow( + webView.CreationProperties, true /*isNewWindowRequest*/); + main_window.OnWebViewFirstInitialized = () => + { + using (deferral) + { + args.Handled = true; + args.NewWindow = main_window.webView.CoreWebView2; + } + }; + main_window.Show(); + } + }; +#endif return; } @@ -2308,87 +2394,99 @@ void PerfInfoCmdExecuted(object target, ExecutedRoutedEventArgs e) } // - string AppendFrameInfo(CoreWebView2FrameInfo frameInfo, string type, string mainFrameId, string firstLevelFrameId) { +#if USE_WEBVIEW2_EXPERIMENTAL + string AppendFrameInfo(CoreWebView2FrameInfo frameInfo) { string id = frameInfo.FrameId.ToString(); + string kind = frameInfo.FrameKind.ToString(); string name = String.IsNullOrEmpty(frameInfo.Name) ? "none" : frameInfo.Name; string source = String.IsNullOrEmpty(frameInfo.Source) ? "none" : frameInfo.Source; string parentId = frameInfo.ParentFrameInfo == null ? "none" : frameInfo.ParentFrameInfo.FrameId.ToString(); + string type = "other frame"; + + CoreWebView2FrameInfo mainFrame = GetAncestorMainFrameInfo(frameInfo); + string mainFrameId = mainFrame.FrameId.ToString(); + if (frameInfo == mainFrame) { + type = "main frame"; + } + + CoreWebView2FrameInfo firstLevelFrame = GetAncestorFirstLevelFrameInfo(frameInfo); + string firstLevelFrameId = firstLevelFrame == null ? "none" : firstLevelFrame.FrameId.ToString(); + if (frameInfo == firstLevelFrame) { + type = "first level frame"; + } return $"{{frame Id:{id} " + $"| frame Name: {name} " + $"| frame Type: {type} " + - $"| parent frame Id: {parentId} " + + $"| parent frame Id: {parentId} \n" + $"| ancestor main frame Id: {mainFrameId} " + - $"| ancestor first level frame Id: {firstLevelFrameId} " + - $"| frame Kind: {frameInfo.FrameKind} " + + $"| ancestor first level frame Id: {firstLevelFrameId} \n" + + $"| frame Kind: {kind} " + $"| frame Source: \"{source}\"}}\n"; } + CoreWebView2FrameInfo GetAncestorMainFrameInfo(CoreWebView2FrameInfo frameInfo) { + while (frameInfo.ParentFrameInfo != null) { + frameInfo = frameInfo.ParentFrameInfo; + } + return frameInfo; + } + + CoreWebView2FrameInfo GetAncestorFirstLevelFrameInfo(CoreWebView2FrameInfo frameInfo) { + if (frameInfo.ParentFrameInfo == null) { + return null; + } + + CoreWebView2FrameInfo firstLevelFrameInfo = null; + CoreWebView2FrameInfo mainFrameInfo = null; + while (frameInfo != null) { + firstLevelFrameInfo = mainFrameInfo; + mainFrameInfo = frameInfo; + frameInfo = frameInfo.ParentFrameInfo; + } + return firstLevelFrameInfo; + } +#endif + private async void ProcessFrameInfoCmdExecuted(object target, ExecutedRoutedEventArgs e) { +#if USE_WEBVIEW2_EXPERIMENTAL try { // IReadOnlyList processList = await webView.CoreWebView2.Environment.GetProcessInfosWithDetailsAsync(); - int processListCount = processList.Count; - string rendererProcessInfosStr = $"{processListCount} process(es) found in total\n\n"; - string otherProcessInfosStr = $"\nRemaining Process Infos:\n"; + int processCount = processList.Count; + string rendererProcessInfos = ""; + string otherProcessInfos = ""; int rendererProcessCount = 0; - for (int i = 0; i < processListCount; ++i) + for (int i = 0; i < processCount; ++i) { CoreWebView2ProcessKind kind = processList[i].Kind; int processId = processList[i].ProcessId; if (kind == CoreWebView2ProcessKind.Renderer) { int frameInfoCount = 0; - string frameInfosStr = ""; + string frameInfos = ""; // IReadOnlyList frameInfoList = processList[i].AssociatedFrameInfos; foreach (CoreWebView2FrameInfo frameInfo in frameInfoList) { - string ancestorMainFrameId = "none"; - string ancestorFirstLevelFrameId = "none"; - CoreWebView2FrameInfo parentFrameInfo = frameInfo.ParentFrameInfo; frameInfoCount++; - // If the frame has no parent, then it's a main frame. - if (parentFrameInfo == null) - { - ancestorMainFrameId = frameInfo.FrameId.ToString(); - frameInfosStr += AppendFrameInfo(frameInfo, "main frame", ancestorMainFrameId, ancestorFirstLevelFrameId); - continue; - } - - CoreWebView2FrameInfo mainFrameInfo = parentFrameInfo; - CoreWebView2FrameInfo firstLevelFrameInfo = frameInfo; - // If the frame's parent has no parent frame, then it's a first level frame. - if (mainFrameInfo.ParentFrameInfo == null) { - ancestorMainFrameId = mainFrameInfo.FrameId.ToString(); - ancestorFirstLevelFrameId = firstLevelFrameInfo.FrameId.ToString(); - frameInfosStr += AppendFrameInfo(frameInfo, "first level frame", ancestorMainFrameId, ancestorFirstLevelFrameId); - continue; - } - // For other child frames, we traverse the parent frame until find the ancestor main frame. - while (mainFrameInfo.ParentFrameInfo != null) { - firstLevelFrameInfo = mainFrameInfo; - mainFrameInfo = mainFrameInfo.ParentFrameInfo; - } - - ancestorMainFrameId = mainFrameInfo.FrameId.ToString(); - ancestorFirstLevelFrameId = firstLevelFrameInfo.FrameId.ToString(); - frameInfosStr += AppendFrameInfo(frameInfo, "other child frame", ancestorMainFrameId, ancestorFirstLevelFrameId); + frameInfos += AppendFrameInfo(frameInfo); } // - string rendererProcessInfoStr = $"{frameInfoCount} frame info(s) found in renderer process ID: {processId}\n {frameInfosStr}"; - rendererProcessInfosStr += $"{rendererProcessInfoStr} \n"; + string rendererProcessInfo = $"{frameInfoCount} frame info(s) found in renderer process ID: {processId}\n {frameInfos}"; + rendererProcessInfos += $"{rendererProcessInfo} \n"; rendererProcessCount++; } else { - otherProcessInfosStr += $"Process ID: {processId} | Process Kind: {kind}\n"; + otherProcessInfos += $"Process ID: {processId} | Process Kind: {kind}\n"; } } // - string message = $"{rendererProcessCount} renderer process(es) found, {rendererProcessInfosStr + otherProcessInfosStr}"; + string message = $"{processCount} process(es) found in total, from which {rendererProcessCount} renderer process(es) found\n\n" + + $"{rendererProcessInfos}\nRemaining Process Infos:\n{otherProcessInfos}"; MessageBox.Show(this, message, "Process Info with Associated Frames"); } catch (NotImplementedException exception) @@ -2396,6 +2494,9 @@ private async void ProcessFrameInfoCmdExecuted(object target, ExecutedRoutedEven MessageBox.Show(this, "GetProcessInfosWithDetailsAsync Failed: " + exception.Message, "Process Info with Associated Frames"); } +#else + await Task.CompletedTask; +#endif } void CreateDownloadsButtonCmdExecuted(object target, ExecutedRoutedEventArgs e) { @@ -2858,6 +2959,7 @@ void BrowserAcceleratorKeyEnabledCommandExecuted(object target, ExecutedRoutedEv async void InjectScriptWithResultCmdExecuted(object target, ExecutedRoutedEventArgs e) { +#if USE_WEBVIEW2_EXPERIMENTAL // var dialog = new TextInputDialog( title: "Inject Script With Result", @@ -2893,6 +2995,9 @@ async void InjectScriptWithResultCmdExecuted(object target, ExecutedRoutedEventA } } // +#else + await Task.CompletedTask; +#endif } string NameOfPermissionKind(CoreWebView2PermissionKind kind) @@ -3116,6 +3221,8 @@ await WebViewProfile.SetPermissionStateAsync( webView.Reload(); } + +#if USE_WEBVIEW2_EXPERIMENTAL // void WebView_NotificationReceived(object sender, CoreWebView2NotificationReceivedEventArgs args) { @@ -3161,5 +3268,17 @@ void WebView_NotificationReceived(object sender, CoreWebView2NotificationReceive }, null); } // +#endif + + // + void OpenSaveAsDialogExecuted(object target, ExecutedRoutedEventArgs e) + { + } + // + // + void SaveAsSilentExecuted(object target, ExecutedRoutedEventArgs e) + { + } + // } } diff --git a/SampleApps/WebView2WpfBrowser/SaveAsDialog.xaml b/SampleApps/WebView2WpfBrowser/SaveAsDialog.xaml new file mode 100644 index 00000000..0c832d64 --- /dev/null +++ b/SampleApps/WebView2WpfBrowser/SaveAsDialog.xaml @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + +