diff --git a/SampleApps/WebView2APISample/AppWindow.cpp b/SampleApps/WebView2APISample/AppWindow.cpp index 495ff63e..2c998e1a 100644 --- a/SampleApps/WebView2APISample/AppWindow.cpp +++ b/SampleApps/WebView2APISample/AppWindow.cpp @@ -47,6 +47,11 @@ #include "ScenarioNonClientRegionSupport.h" #include "ScenarioNotificationReceived.h" #include "ScenarioPermissionManagement.h" +#include "ScenarioDedicatedWorker.h" +#include "ScenarioDedicatedWorkerPostMessage.h" +#include "ScenarioServiceWorkerManager.h" +#include "ScenarioServiceWorkerPostMessage.h" +#include "ScenarioSharedWorkerManager.h" #include "ScenarioSaveAs.h" #include "ScenarioScreenCapture.h" #include "ScenarioSharedBuffer.h" @@ -56,6 +61,7 @@ #include "ScenarioVirtualHostMappingForSW.h" #include "ScenarioWebMessage.h" #include "ScenarioWebViewEventMonitor.h" +#include "ScenarioWindowControlsOverlay.h" #include "ScriptComponent.h" #include "SettingsComponent.h" #include "TextInputDialog.h" @@ -204,6 +210,13 @@ AppWindow::AppWindow( LoadStringW(g_hInstance, IDS_APP_TITLE, szTitle, s_maxLoadString); m_appTitle = szTitle; DWORD windowStyle = WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN; + if (m_webviewOption.useWco) + { + windowStyle &= ~WS_OVERLAPPEDWINDOW; + windowStyle |= (WS_POPUP | WS_THICKFRAME | WS_MAXIMIZEBOX | WS_MINIMIZEBOX); + } + + if (userDataFolderParam.length() > 0) { m_userDataFolder = userDataFolderParam; @@ -248,6 +261,13 @@ AppWindow::AppWindow( UpdateCreationModeMenu(); ShowWindow(m_mainWindow, g_nCmdShow); UpdateWindow(m_mainWindow); + if (m_webviewOption.useWco) + { + SetMenu(m_mainWindow, NULL); + SetWindowPos(m_mainWindow, nullptr, 0, 0, 1800, 900, 0); + m_toolbar.Hide(); + } + // If no WebView2 Runtime installed, create new thread to do install/download. // Otherwise just initialize webview. wil::unique_cotaskmem_string version_info; @@ -271,6 +291,7 @@ AppWindow::AppWindow( } } } + AppWindow::~AppWindow() { DeleteObject(m_appBackgroundImageHandle); @@ -666,6 +687,11 @@ bool AppWindow::ExecuteWebViewCommands(WPARAM wParam, LPARAM lParam) NewComponent(this); return true; } + case IDM_SCENARIO_WINDOW_CONTROLS_OVERLAY: + { + NewComponent(this); + return true; + } case IDM_SCENARIO_ACCELERATOR_KEY_PRESSED: { NewComponent(this); @@ -676,6 +702,73 @@ bool AppWindow::ExecuteWebViewCommands(WPARAM wParam, LPARAM lParam) NewComponent(this); return true; } + case IDM_SCENARIO_SERVICE_WORKER_REGISTRATION_REQUESTED: + { + if (!GetComponent()) + { + NewComponent(this); + } + return true; + } + case IDM_SCENARIO_SERVICE_WORKER_POST_MESSAGE: + { + NewComponent(this); + return true; + } + case IDM_SCENARIO_DEDICATED_WORKER: + { + if (!GetComponent()) + { + NewComponent(this); + } + return true; + } + case IDM_SCENARIO_DEDICATED_WORKER_POST_MESSAGE: + { + NewComponent(this); + return true; + } + case IDM_SCENARIO_SHARED_WORKER_MANAGER: + { + if (!GetComponent()) + { + NewComponent(this); + } + return true; + } + case IDM_SCENARIO_GET_SERVICE_WORKER_REGISTRATIONS: + { + auto worker_manager = GetComponent(); + if (!worker_manager) + { + NewComponent(this); + worker_manager = GetComponent(); + } + worker_manager->GetAllServiceWorkerRegistrations(); + return true; + } + case IDM_SCENARIO_GET_SERVICE_WORKER_REGISTERED_FOR_SCOPE: + { + auto worker_manager = GetComponent(); + if (!worker_manager) + { + NewComponent(this); + worker_manager = GetComponent(); + } + worker_manager->GetServiceWorkerRegisteredForScope(); + return true; + } + case IDM_SCENARIO_GET_SHARED_WORKERS: + { + auto worker_manager = GetComponent(); + if (!worker_manager) + { + NewComponent(this); + worker_manager = GetComponent(); + } + worker_manager->GetAllSharedWorkers(); + return true; + } case IDM_SCENARIO_SCREEN_CAPTURE: { NewComponent(this); @@ -1252,11 +1345,11 @@ bool AppWindow::PrintToPdfStream() //! [Start] bool AppWindow::Start(const std::wstring& searchTerm) { - auto webView2Experimental29 = m_webView.try_query(); - CHECK_FEATURE_RETURN(webView2Experimental29); + auto webView2_28 = m_webView.try_query(); + CHECK_FEATURE_RETURN(webView2_28); - wil::com_ptr webView2find; - CHECK_FAILURE(webView2Experimental29->get_Find(&webView2find)); + wil::com_ptr webView2find; + CHECK_FAILURE(webView2_28->get_Find(&webView2find)); SetupFindEventHandlers(webView2find); // Initialize find configuration/settings @@ -1274,7 +1367,7 @@ bool AppWindow::Start(const std::wstring& searchTerm) // Start the find operation CHECK_FAILURE(webView2find->Start( - findOptions.get(), Callback( + findOptions.get(), Callback( [this](HRESULT result) -> HRESULT { return S_OK; }) .Get())); return true; @@ -1284,10 +1377,10 @@ bool AppWindow::Start(const std::wstring& searchTerm) //! [FindNext] bool AppWindow::FindNext() { - auto webView2Experimental29 = m_webView.try_query(); - CHECK_FEATURE_RETURN(webView2Experimental29); - wil::com_ptr webView2find; - CHECK_FAILURE(webView2Experimental29->get_Find(&webView2find)); + auto webView2_28 = m_webView.try_query(); + CHECK_FEATURE_RETURN(webView2_28); + wil::com_ptr webView2find; + CHECK_FAILURE(webView2_28->get_Find(&webView2find)); CHECK_FAILURE(webView2find->FindNext()); return true; @@ -1297,10 +1390,10 @@ bool AppWindow::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)); + auto webView2_28 = m_webView.try_query(); + CHECK_FEATURE_RETURN(webView2_28); + wil::com_ptr webView2find; + CHECK_FAILURE(webView2_28->get_Find(&webView2find)); CHECK_FAILURE(webView2find->FindPrevious()); @@ -1311,10 +1404,10 @@ bool AppWindow::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)); + auto webView2_28 = m_webView.try_query(); + CHECK_FEATURE_RETURN(webView2_28); + wil::com_ptr webView2find; + CHECK_FAILURE(webView2_28->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? @@ -1328,10 +1421,10 @@ bool AppWindow::StopFind() //! [MatchCount] bool AppWindow::GetMatchCount() { - auto webView2Experimental29 = m_webView.try_query(); - CHECK_FEATURE_RETURN(webView2Experimental29); - wil::com_ptr webView2find; - CHECK_FAILURE(webView2Experimental29->get_Find(&webView2find)); + auto webView2_28 = m_webView.try_query(); + CHECK_FEATURE_RETURN(webView2_28); + wil::com_ptr webView2find; + CHECK_FAILURE(webView2_28->get_Find(&webView2find)); int32_t matchCount; CHECK_FAILURE(webView2find->get_MatchCount(&matchCount)); @@ -1345,10 +1438,10 @@ bool AppWindow::GetMatchCount() //! [ActiveMatchIndex] bool AppWindow::GetActiveMatchIndex() { - auto webView2Experimental29 = m_webView.try_query(); - CHECK_FEATURE_RETURN(webView2Experimental29); - wil::com_ptr webView2find; - CHECK_FAILURE(webView2Experimental29->get_Find(&webView2find)); + auto webView2_28 = m_webView.try_query(); + CHECK_FEATURE_RETURN(webView2_28); + wil::com_ptr webView2find; + CHECK_FAILURE(webView2_28->get_Find(&webView2find)); int32_t activeMatchIndex; CHECK_FAILURE(webView2find->get_ActiveMatchIndex(&activeMatchIndex)); @@ -1363,13 +1456,13 @@ bool AppWindow::GetActiveMatchIndex() //! [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 webView2_28 = m_webView.try_query(); + CHECK_FEATURE_RETURN(webView2_28); + wil::com_ptr webView2find; + CHECK_FAILURE(webView2_28->get_Find(&webView2find)); - auto m_env18 = m_webViewEnvironment.try_query(); - CHECK_FEATURE_RETURN(m_env18); + auto m_env15 = m_webViewEnvironment.try_query(); + CHECK_FEATURE_RETURN(m_env15); CHECK_FAILURE(webView2find->Stop()); if (!findOptions) @@ -1381,7 +1474,7 @@ bool AppWindow::IsCaseSensitive() CHECK_FAILURE(findOptions->put_IsCaseSensitive(!caseSensitive)); CHECK_FAILURE(webView2find->Start( - findOptions.get(), Callback( + findOptions.get(), Callback( [this](HRESULT result) -> HRESULT { return S_OK; }) .Get())); return true; @@ -1391,13 +1484,13 @@ bool AppWindow::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 webView2_28 = m_webView.try_query(); + CHECK_FEATURE_RETURN(webView2_28); + wil::com_ptr webView2find; + CHECK_FAILURE(webView2_28->get_Find(&webView2find)); - auto m_env18 = m_webViewEnvironment.try_query(); - CHECK_FEATURE_RETURN(m_env18); + auto m_env15 = m_webViewEnvironment.try_query(); + CHECK_FEATURE_RETURN(m_env15); CHECK_FAILURE(webView2find->Stop()); if (!findOptions) @@ -1408,7 +1501,7 @@ bool AppWindow::ShouldHighlightAllMatches() CHECK_FAILURE(findOptions->get_ShouldHighlightAllMatches(&shouldHighlightAllMatches)); CHECK_FAILURE(findOptions->put_ShouldHighlightAllMatches(!shouldHighlightAllMatches)); CHECK_FAILURE(webView2find->Start( - findOptions.get(), Callback( + findOptions.get(), Callback( [this](HRESULT result) -> HRESULT { return S_OK; }) .Get())); return true; @@ -1418,13 +1511,13 @@ bool AppWindow::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 webView2_28 = m_webView.try_query(); + CHECK_FEATURE_RETURN(webView2_28); + wil::com_ptr webView2find; + CHECK_FAILURE(webView2_28->get_Find(&webView2find)); - auto m_env18 = m_webViewEnvironment.try_query(); - CHECK_FEATURE_RETURN(m_env18); + auto m_env15 = m_webViewEnvironment.try_query(); + CHECK_FEATURE_RETURN(m_env15); CHECK_FAILURE(webView2find->Stop()); if (!findOptions) @@ -1435,7 +1528,7 @@ bool AppWindow::ShouldMatchWord() findOptions->get_ShouldMatchWord(&shouldMatchWord); CHECK_FAILURE(findOptions->put_ShouldMatchWord(!shouldMatchWord)); CHECK_FAILURE(webView2find->Start( - findOptions.get(), Callback( + findOptions.get(), Callback( [this](HRESULT result) -> HRESULT { return S_OK; }) .Get())); return true; @@ -1445,13 +1538,13 @@ bool AppWindow::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 webView2_28 = m_webView.try_query(); + CHECK_FEATURE_RETURN(webView2_28); + wil::com_ptr webView2find; + CHECK_FAILURE(webView2_28->get_Find(&webView2find)); - auto m_env18 = m_webViewEnvironment.try_query(); - CHECK_FEATURE_RETURN(m_env18); + auto m_env15 = m_webViewEnvironment.try_query(); + CHECK_FEATURE_RETURN(m_env15); CHECK_FAILURE(webView2find->Stop()); if (!findOptions) @@ -1463,7 +1556,7 @@ bool AppWindow::SuppressDefaultFindDialog() CHECK_FAILURE(findOptions->put_SuppressDefaultFindDialog(!suppressDefaultDialog)); CHECK_FAILURE(webView2find->Stop()); CHECK_FAILURE(webView2find->Start( - findOptions.get(), Callback( + findOptions.get(), Callback( [this](HRESULT result) -> HRESULT { return S_OK; }) .Get())); return true; @@ -1473,16 +1566,16 @@ bool AppWindow::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)); + auto webView2_28 = m_webView.try_query(); + CHECK_FEATURE_RETURN(webView2_28); + wil::com_ptr webView2find; + CHECK_FAILURE(webView2_28->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); + auto m_env15 = m_webViewEnvironment.try_query(); + CHECK_FEATURE_RETURN(m_env15); CHECK_FAILURE(webView2find->Stop()); if (!findOptions) @@ -1491,20 +1584,20 @@ bool AppWindow::FindTerm() } CHECK_FAILURE(findOptions->put_FindTerm(dialog.input.c_str())); CHECK_FAILURE(webView2find->Start( - findOptions.get(), Callback( + findOptions.get(), Callback( [this](HRESULT result) -> HRESULT { return S_OK; }) .Get())); return true; } //! [FindTerm] -wil::com_ptr AppWindow::SetDefaultFindOptions() +wil::com_ptr AppWindow::SetDefaultFindOptions() { - auto m_env18 = m_webViewEnvironment.try_query(); + auto m_env15 = m_webViewEnvironment.try_query(); // Initialize find configuration/settings - wil::com_ptr findOptions; - CHECK_FAILURE(m_env18->CreateFindOptions(&findOptions)); + wil::com_ptr findOptions; + CHECK_FAILURE(m_env15->CreateFindOptions(&findOptions)); CHECK_FAILURE(findOptions->put_FindTerm(L"Webview2")); CHECK_FAILURE(findOptions->put_IsCaseSensitive(false)); CHECK_FAILURE(findOptions->put_ShouldMatchWord(false)); @@ -1514,11 +1607,11 @@ wil::com_ptr AppWindow::SetDefaultFindOpti return findOptions; } -void AppWindow::SetupFindEventHandlers(wil::com_ptr webView2find) +void AppWindow::SetupFindEventHandlers(wil::com_ptr webView2find) { CHECK_FAILURE(webView2find->add_MatchCountChanged( - Callback( - [this](ICoreWebView2ExperimentalFind* sender, IUnknown* args) -> HRESULT + Callback( + [this](ICoreWebView2Find* sender, IUnknown* args) -> HRESULT { int matchCount = 0; if (sender) @@ -1531,8 +1624,8 @@ void AppWindow::SetupFindEventHandlers(wil::com_ptradd_ActiveMatchIndexChanged( - Callback( - [this](ICoreWebView2ExperimentalFind* sender, IUnknown* args) -> HRESULT + Callback( + [this](ICoreWebView2Find* sender, IUnknown* args) -> HRESULT { int activeIndex = -1; if (sender) @@ -1957,6 +2050,20 @@ HRESULT AppWindow::OnCreateCoreWebView2ControllerCompleted( SetAppIcon(inPrivate); } //! [CoreWebView2Profile] + //! [WindowControlsOverlay] + if (m_webviewOption.useWco) + { + auto webview2Experimental31 = m_webView.try_query(); + if (webview2Experimental31) + { + wil::com_ptr wco; + CHECK_FAILURE(webview2Experimental31->get_WindowControlsOverlay(&wco)); + CHECK_FAILURE(wco->put_IsEnabled(true)); + CHECK_FAILURE(wco->put_Height(48)); + CHECK_FAILURE(wco->put_BackgroundColor({0, 0, 0, 0})); + } + } + //! [WindowControlsOverlay] // Create components. These will be deleted when the WebView is closed. NewComponent(this); NewComponent(this); @@ -1969,6 +2076,7 @@ HRESULT AppWindow::OnCreateCoreWebView2ControllerCompleted( m_creationModeId == IDM_CREATION_MODE_TARGET_DCOMP); NewComponent(this); NewComponent(this, &m_toolbar); + m_webView3 = coreWebView2.try_query(); if (m_webView3) { @@ -2380,10 +2488,12 @@ void AppWindow::ResizeEverything() GetClientRect(m_mainWindow, &availableBounds); if (!m_containsFullscreenElement + && !m_webviewOption.useWco ) { availableBounds = m_toolbar.Resize(availableBounds); } + if (auto view = GetComponent()) { view->SetBounds(availableBounds); diff --git a/SampleApps/WebView2APISample/AppWindow.h b/SampleApps/WebView2APISample/AppWindow.h index fdb20380..4fab7873 100644 --- a/SampleApps/WebView2APISample/AppWindow.h +++ b/SampleApps/WebView2APISample/AppWindow.h @@ -39,17 +39,20 @@ struct WebViewCreateOption WebViewCreateEntry entry = WebViewCreateEntry::OTHER; bool useOSRegion = false; std::optional bg_color; + bool useWco = false; WebViewCreateOption() { } WebViewCreateOption( const std::wstring& profile_, bool inPrivate, const std::wstring& downloadPath, - const std::wstring& scriptLocale_, WebViewCreateEntry entry_, bool useOSRegion_ - ) + const std::wstring& scriptLocale_, WebViewCreateEntry entry_, bool useOSRegion_, + bool useWco_ = false, const std::optional& bg_color_ = std::nullopt) : profile(profile_), isInPrivate(inPrivate), downloadPath(downloadPath), - scriptLocale(scriptLocale_), entry(entry_), useOSRegion(useOSRegion_) + scriptLocale(scriptLocale_), entry(entry_), useOSRegion(useOSRegion_), + useWco(useWco_), bg_color(bg_color_) { } + WebViewCreateOption(const WebViewCreateOption& opt) { profile = opt.profile; @@ -58,6 +61,8 @@ struct WebViewCreateOption scriptLocale = opt.scriptLocale; entry = opt.entry; useOSRegion = opt.useOSRegion; + useWco = opt.useWco; + bg_color = opt.bg_color; } void PopupDialog(AppWindow* app); }; @@ -222,11 +227,11 @@ class AppWindow bool ShouldMatchWord(); bool SuppressDefaultFindDialog(); bool IsCaseSensitive(); - wil::com_ptr SetDefaultFindOptions(); - void SetupFindEventHandlers(wil::com_ptr webView2find); + wil::com_ptr SetDefaultFindOptions(); + void SetupFindEventHandlers(wil::com_ptr webView2find); // Find on Page member std::wstring m_findOnPageLastSearchTerm; - wil::com_ptr findOptions; + wil::com_ptr findOptions; EventRegistrationToken m_activeMatchIndexChangedToken = {}; EventRegistrationToken m_matchCountChangedToken = {}; diff --git a/SampleApps/WebView2APISample/ScenarioDedicatedWorker.cpp b/SampleApps/WebView2APISample/ScenarioDedicatedWorker.cpp new file mode 100644 index 00000000..83616ed1 --- /dev/null +++ b/SampleApps/WebView2APISample/ScenarioDedicatedWorker.cpp @@ -0,0 +1,129 @@ +// 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 "ScenarioDedicatedWorker.h" + +using namespace Microsoft::WRL; + +ScenarioDedicatedWorker::ScenarioDedicatedWorker(AppWindow* appWindow) : m_appWindow(appWindow) +{ + //! [DedicatedWorkerCreated] + m_appWindow->GetWebView()->QueryInterface(IID_PPV_ARGS(&m_webView2Experimental_30)); + CHECK_FEATURE_RETURN_EMPTY(m_webView2Experimental_30); + + CHECK_FAILURE(m_webView2Experimental_30->add_DedicatedWorkerCreated( + Callback( + [this]( + ICoreWebView2* sender, + ICoreWebView2ExperimentalDedicatedWorkerCreatedEventArgs* args) + { + wil::com_ptr dedicatedWorker; + CHECK_FAILURE(args->get_Worker(&dedicatedWorker)); + + wil::unique_cotaskmem_string scriptUri; + CHECK_FAILURE(dedicatedWorker->get_ScriptUri(&scriptUri)); + + std::wstring scriptUriStr(scriptUri.get()); + m_appWindow->AsyncMessageBox(scriptUriStr, L"Dedicated worker is created"); + + // Subscribe to worker destroying event + dedicatedWorker->add_Destroying( + Callback( + [this, scriptUriStr]( + ICoreWebView2ExperimentalDedicatedWorker* sender, + IUnknown* args) -> HRESULT + { + /*Cleanup on worker destruction*/ + m_appWindow->AsyncMessageBox( + scriptUriStr, L"Dedicated worker is destroyed"); + return S_OK; + }) + .Get(), + nullptr); + + return S_OK; + }) + .Get(), + &m_dedicatedWorkerCreatedToken)); + //! [DedicatedWorkerCreated] + + wil::com_ptr m_webView2_4; + m_appWindow->GetWebView()->QueryInterface(IID_PPV_ARGS(&m_webView2_4)); + CHECK_FEATURE_RETURN_EMPTY(m_webView2_4); + + CHECK_FAILURE(m_webView2_4->add_FrameCreated( + Callback( + [this](ICoreWebView2* sender, ICoreWebView2FrameCreatedEventArgs* args) -> HRESULT + { + wil::com_ptr webviewFrame; + CHECK_FAILURE(args->get_Frame(&webviewFrame)); + + wil::com_ptr m_frameExperimental_9 = + webviewFrame.try_query(); + + m_frameExperimental_9->add_DedicatedWorkerCreated( + Callback( + [this]( + ICoreWebView2Frame* sender, + ICoreWebView2ExperimentalDedicatedWorkerCreatedEventArgs* args) + -> HRESULT + { + // frameInfo that created the worker. + wil::com_ptr frameInfo; + CHECK_FAILURE(args->get_OriginalSourceFrameInfo(&frameInfo)); + + wil::com_ptr frameInfo2; + CHECK_FAILURE(frameInfo->QueryInterface(IID_PPV_ARGS(&frameInfo2))); + + wil::unique_cotaskmem_string frameSource; + CHECK_FAILURE(frameInfo->get_Source(&frameSource)); + + UINT32 source_frameId; + CHECK_FAILURE(frameInfo2->get_FrameId(&source_frameId)); + + wil::com_ptr + dedicatedWorker; + CHECK_FAILURE(args->get_Worker(&dedicatedWorker)); + + wil::unique_cotaskmem_string scriptUri; + CHECK_FAILURE(dedicatedWorker->get_ScriptUri(&scriptUri)); + + std::wstring scriptUriStr(scriptUri.get()); + m_appWindow->AsyncMessageBox( + scriptUriStr, L"Dedicated worker is created"); + + // Subscribe to worker destroying event + dedicatedWorker->add_Destroying( + Callback< + ICoreWebView2ExperimentalDedicatedWorkerDestroyingEventHandler>( + [this, scriptUriStr]( + ICoreWebView2ExperimentalDedicatedWorker* sender, + IUnknown* args) -> HRESULT + { + /*Cleanup on worker destruction*/ + m_appWindow->AsyncMessageBox( + scriptUriStr, L"Dedicated worker is destroyed"); + return S_OK; + }) + .Get(), + nullptr); + + return S_OK; + }) + .Get(), + nullptr); + + return S_OK; + }) + .Get(), + nullptr)); +} + +ScenarioDedicatedWorker::~ScenarioDedicatedWorker() +{ + m_webView2Experimental_30->remove_DedicatedWorkerCreated(m_dedicatedWorkerCreatedToken); +} diff --git a/SampleApps/WebView2APISample/ScenarioDedicatedWorker.h b/SampleApps/WebView2APISample/ScenarioDedicatedWorker.h new file mode 100644 index 00000000..9c206e9c --- /dev/null +++ b/SampleApps/WebView2APISample/ScenarioDedicatedWorker.h @@ -0,0 +1,20 @@ +// 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 "AppWindow.h" +#include "ComponentBase.h" + +class ScenarioDedicatedWorker : public ComponentBase +{ +public: + ScenarioDedicatedWorker(AppWindow* appWindow); + ~ScenarioDedicatedWorker() override; + +private: + AppWindow* m_appWindow; + wil::com_ptr m_webView2Experimental_30; + EventRegistrationToken m_dedicatedWorkerCreatedToken = {}; +}; diff --git a/SampleApps/WebView2APISample/ScenarioDedicatedWorkerPostMessage.cpp b/SampleApps/WebView2APISample/ScenarioDedicatedWorkerPostMessage.cpp new file mode 100644 index 00000000..7e088899 --- /dev/null +++ b/SampleApps/WebView2APISample/ScenarioDedicatedWorkerPostMessage.cpp @@ -0,0 +1,123 @@ +// 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 "CheckFailure.h" +#include "TextInputDialog.h" + +#include "ScenarioDedicatedWorkerPostMessage.h" + +using namespace Microsoft::WRL; + +static constexpr WCHAR c_samplePath[] = L"ScenarioDedicatedWorkerPostMessage.html"; + +ScenarioDedicatedWorkerPostMessage::ScenarioDedicatedWorkerPostMessage(AppWindow* appWindow) + : m_appWindow(appWindow) +{ + //! [DedicatedWorkerCreated] + m_appWindow->GetWebView()->QueryInterface(IID_PPV_ARGS(&m_webView2Experimental_30)); + CHECK_FEATURE_RETURN_EMPTY(m_webView2Experimental_30); + + CHECK_FAILURE(m_webView2Experimental_30->add_DedicatedWorkerCreated( + Callback( + [this]( + ICoreWebView2* sender, + ICoreWebView2ExperimentalDedicatedWorkerCreatedEventArgs* args) + { + wil::com_ptr dedicatedWorker; + CHECK_FAILURE(args->get_Worker(&dedicatedWorker)); + + wil::unique_cotaskmem_string scriptUri; + CHECK_FAILURE(dedicatedWorker->get_ScriptUri(&scriptUri)); + + std::wstring scriptUriStr(scriptUri.get()); + m_appWindow->AsyncMessageBox(scriptUriStr, L"Dedicated worker is created"); + + SetupEventsOnDedicatedWorker(dedicatedWorker); + ComputeWithDedicatedWorker(dedicatedWorker); + + return S_OK; + }) + .Get(), + &m_dedicatedWorkerCreatedToken)); + //! [DedicatedWorkerCreated] + + // Turn off this scenario if we navigate away from the sample page. + CHECK_FAILURE(m_appWindow->GetWebView()->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)); + + m_sampleUri = m_appWindow->GetLocalUri(c_samplePath); + CHECK_FAILURE(m_appWindow->GetWebView()->Navigate(m_sampleUri.c_str())); +} + +void ScenarioDedicatedWorkerPostMessage::SetupEventsOnDedicatedWorker( + wil::com_ptr dedicatedWorker) +{ + //! [WebMessageReceived] + dedicatedWorker->add_WebMessageReceived( + Callback( + [this]( + ICoreWebView2ExperimentalDedicatedWorker* sender, + ICoreWebView2WebMessageReceivedEventArgs* args) -> HRESULT + { + wil::unique_cotaskmem_string scriptUri; + CHECK_FAILURE(args->get_Source(&scriptUri)); + + wil::unique_cotaskmem_string messageRaw; + CHECK_FAILURE(args->TryGetWebMessageAsString(&messageRaw)); + std::wstring messageFromWorker = messageRaw.get(); + + std::wstringstream message{}; + message << L"Dedicated Worker: " << std::endl << scriptUri.get() << std::endl; + message << std::endl; + message << L"Message: " << std::endl << messageFromWorker << std::endl; + m_appWindow->AsyncMessageBox(message.str(), L"Message from Dedicated Worker"); + + return S_OK; + }) + .Get(), + nullptr); + //! [WebMessageReceived] +} + +void ScenarioDedicatedWorkerPostMessage::ComputeWithDedicatedWorker( + wil::com_ptr dedicatedWorker) +{ + //! [PostWebMessageAsJson] + // Do not block from event handler + m_appWindow->RunAsync( + [this, dedicatedWorker] + { + TextInputDialog dialog( + m_appWindow->GetMainWindow(), L"Post Web Message JSON", L"Web message JSON", + L"Enter the web message as JSON.", + L"{\"command\":\"ADD\",\"first\":2,\"second\":3}"); + // Ex: {"command":"ADD","first":2,"second":3} + if (dialog.confirmed) + { + dedicatedWorker->PostWebMessageAsJson(dialog.input.c_str()); + } + }); + //! [PostWebMessageAsJson] +} + +ScenarioDedicatedWorkerPostMessage::~ScenarioDedicatedWorkerPostMessage() +{ + m_webView2Experimental_30->remove_DedicatedWorkerCreated(m_dedicatedWorkerCreatedToken); + m_appWindow->GetWebView()->remove_ContentLoading(m_contentLoadingToken); +} diff --git a/SampleApps/WebView2APISample/ScenarioDedicatedWorkerPostMessage.h b/SampleApps/WebView2APISample/ScenarioDedicatedWorkerPostMessage.h new file mode 100644 index 00000000..c465679f --- /dev/null +++ b/SampleApps/WebView2APISample/ScenarioDedicatedWorkerPostMessage.h @@ -0,0 +1,27 @@ +// 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 "AppWindow.h" +#include "ComponentBase.h" + +class ScenarioDedicatedWorkerPostMessage : public ComponentBase +{ +public: + ScenarioDedicatedWorkerPostMessage(AppWindow* appWindow); + ~ScenarioDedicatedWorkerPostMessage() override; + +private: + void SetupEventsOnDedicatedWorker( + wil::com_ptr dedicatedWorker); + void ComputeWithDedicatedWorker( + wil::com_ptr dedicatedWorker); + + AppWindow* m_appWindow; + wil::com_ptr m_webView2Experimental_30; + std::wstring m_sampleUri; + EventRegistrationToken m_contentLoadingToken = {}; + EventRegistrationToken m_dedicatedWorkerCreatedToken = {}; +}; diff --git a/SampleApps/WebView2APISample/ScenarioServiceWorkerManager.cpp b/SampleApps/WebView2APISample/ScenarioServiceWorkerManager.cpp new file mode 100644 index 00000000..8df4726f --- /dev/null +++ b/SampleApps/WebView2APISample/ScenarioServiceWorkerManager.cpp @@ -0,0 +1,291 @@ +// 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 "CheckFailure.h" +#include "TextInputDialog.h" + +#include "ScenarioServiceWorkerManager.h" + +using namespace Microsoft::WRL; + +ScenarioServiceWorkerManager::ScenarioServiceWorkerManager(AppWindow* appWindow) + : m_appWindow(appWindow), m_webView(appWindow->GetWebView()) +{ + CreateServiceWorkerManager(); + SetupEventsOnWebview(); +} + +void ScenarioServiceWorkerManager::CreateServiceWorkerManager() +{ + //! [ServiceWorkerManager] + auto webView2_13 = m_webView.try_query(); + CHECK_FEATURE_RETURN_EMPTY(webView2_13); + + wil::com_ptr webView2Profile; + CHECK_FAILURE(webView2_13->get_Profile(&webView2Profile)); + auto webViewExperimentalProfile13 = + webView2Profile.try_query(); + CHECK_FEATURE_RETURN_EMPTY(webViewExperimentalProfile13); + CHECK_FAILURE( + webViewExperimentalProfile13->get_ServiceWorkerManager(&m_serviceWorkerManager)); + //! [ServiceWorkerManager] +} + +void ScenarioServiceWorkerManager::SetupEventsOnWebview() +{ + if (!m_serviceWorkerManager) + { + return; + } + + //! [ServiceWorkerRegistered] + CHECK_FAILURE(m_serviceWorkerManager->add_ServiceWorkerRegistered( + Callback( + [this]( + ICoreWebView2ExperimentalServiceWorkerManager* sender, + ICoreWebView2ExperimentalServiceWorkerRegisteredEventArgs* args) + { + wil::com_ptr + serviceWorkerRegistration; + CHECK_FAILURE(args->get_ServiceWorkerRegistration(&serviceWorkerRegistration)); + + if (serviceWorkerRegistration) + { + wil::unique_cotaskmem_string scopeUri; + CHECK_FAILURE(serviceWorkerRegistration->get_ScopeUri(&scopeUri)); + std::wstring scopeUriStr(scopeUri.get()); + + wil::unique_cotaskmem_string origin; + CHECK_FAILURE(serviceWorkerRegistration->get_Origin(&origin)); + + wil::unique_cotaskmem_string topLevelOrigin; + CHECK_FAILURE( + serviceWorkerRegistration->get_TopLevelOrigin(&topLevelOrigin)); + + // Subscribe to worker registration unregistering event + serviceWorkerRegistration->add_Unregistering( + Callback< + ICoreWebView2ExperimentalServiceWorkerRegistrationUnregisteringEventHandler>( + [this, scopeUriStr]( + ICoreWebView2ExperimentalServiceWorkerRegistration* sender, + IUnknown* args) -> HRESULT + { + /*Cleanup on worker registration destruction*/ + m_appWindow->AsyncMessageBox( + scopeUriStr, L"Service worker is unregistered"); + return S_OK; + }) + .Get(), + nullptr); + + wil::com_ptr serviceWorker; + CHECK_FAILURE( + serviceWorkerRegistration->get_ActiveServiceWorker(&serviceWorker)); + + if (serviceWorker) + { + wil::unique_cotaskmem_string scriptUri; + CHECK_FAILURE(serviceWorker->get_ScriptUri(&scriptUri)); + std::wstring scriptUriStr(scriptUri.get()); + + // Subscribe to worker destroying event + serviceWorker->add_Destroying( + Callback< + ICoreWebView2ExperimentalServiceWorkerDestroyingEventHandler>( + [this, scriptUriStr]( + ICoreWebView2ExperimentalServiceWorker* sender, + IUnknown* args) -> HRESULT + { + /*Cleanup on worker destruction*/ + m_appWindow->AsyncMessageBox( + scriptUriStr, L"Service worker is destroyed"); + return S_OK; + }) + .Get(), + nullptr); + } + else + { + CHECK_FAILURE(serviceWorkerRegistration->add_ServiceWorkerActivated( + Callback< + ICoreWebView2ExperimentalServiceWorkerActivatedEventHandler>( + [this]( + ICoreWebView2ExperimentalServiceWorkerRegistration* sender, + ICoreWebView2ExperimentalServiceWorkerActivatedEventArgs* + args) -> HRESULT + { + wil::com_ptr + serviceWorker; + CHECK_FAILURE( + args->get_ActiveServiceWorker(&serviceWorker)); + wil::unique_cotaskmem_string scriptUri; + CHECK_FAILURE(serviceWorker->get_ScriptUri(&scriptUri)); + std::wstring scriptUriStr(scriptUri.get()); + + // Subscribe to worker destroying event + serviceWorker->add_Destroying( + Callback< + ICoreWebView2ExperimentalServiceWorkerDestroyingEventHandler>( + [this, scriptUriStr]( + ICoreWebView2ExperimentalServiceWorker* sender, + IUnknown* args) -> HRESULT + { + /*Cleanup on worker destruction*/ + m_appWindow->AsyncMessageBox( + scriptUriStr, + L"Service worker is destroyed"); + return S_OK; + }) + .Get(), + nullptr); + + m_appWindow->AsyncMessageBox( + L"Service worker is activated", L"Service worker"); + + return S_OK; + }) + .Get(), + nullptr)); + } + + m_appWindow->AsyncMessageBox(scopeUriStr, L"Service worker is registered"); + } + + return S_OK; + }) + .Get(), + &m_serviceWorkerRegisteredToken)); + //! [ServiceWorkerRegistered] +} + +void ScenarioServiceWorkerManager::GetAllServiceWorkerRegistrations() +{ + CHECK_FEATURE_RETURN_EMPTY(m_serviceWorkerManager); + CHECK_FAILURE(m_serviceWorkerManager->GetServiceWorkerRegistrations( + Callback( + [this]( + HRESULT error, ICoreWebView2ExperimentalServiceWorkerRegistrationCollectionView* + workerRegistrationCollection) -> HRESULT + { + UINT32 workersCount = 0; + CHECK_FAILURE(workerRegistrationCollection->get_Count(&workersCount)); + + std::wstringstream message{}; + message << L"Number of service workers registered: " << workersCount + << std::endl; + + for (UINT32 i = 0; i < workersCount; i++) + { + ComPtr + serviceWorkerRegistration; + CHECK_FAILURE(workerRegistrationCollection->GetValueAtIndex( + i, &serviceWorkerRegistration)); + + wil::unique_cotaskmem_string scopeUri; + CHECK_FAILURE(serviceWorkerRegistration->get_ScopeUri(&scopeUri)); + + wil::unique_cotaskmem_string origin; + CHECK_FAILURE(serviceWorkerRegistration->get_Origin(&origin)); + + wil::unique_cotaskmem_string topLevelOrigin; + CHECK_FAILURE( + serviceWorkerRegistration->get_TopLevelOrigin(&topLevelOrigin)); + + message << L"ScopeUri: " << scopeUri.get() << std::endl; + message << L"Origin: " << origin.get() << std::endl; + message << L"TopLevelOrigin: " << topLevelOrigin.get() << std::endl; + } + + m_appWindow->AsyncMessageBox( + std::move(message.str()), L"Registered service workers"); + + return S_OK; + }) + .Get())); +} + +void ScenarioServiceWorkerManager::GetServiceWorkerRegisteredForScope() +{ + CHECK_FEATURE_RETURN_EMPTY(m_serviceWorkerManager); + TextInputDialog dialog( + m_appWindow->GetMainWindow(), L"Service Worker", L"Scope:", + L"Specify a scope to get the service worker", L""); + + if (dialog.confirmed) + { + CHECK_FAILURE(m_serviceWorkerManager->GetServiceWorkerRegistrationsForScope( + dialog.input.c_str(), + Callback( + [this]( + HRESULT error, + ICoreWebView2ExperimentalServiceWorkerRegistrationCollectionView* + workerRegistrationCollection) -> HRESULT + { + CHECK_FAILURE(error); + UINT32 workersCount = 0; + CHECK_FAILURE(workerRegistrationCollection->get_Count(&workersCount)); + + std::wstringstream message{}; + message << L"Number of service workers registered for the given scope: " + << workersCount << std::endl; + + for (UINT32 i = 0; i < workersCount; i++) + { + Microsoft::WRL::ComPtr< + ICoreWebView2ExperimentalServiceWorkerRegistration> + serviceWorkerRegistration; + CHECK_FAILURE(workerRegistrationCollection->GetValueAtIndex( + i, &serviceWorkerRegistration)); + + wil::com_ptr serviceWorker; + CHECK_FAILURE( + serviceWorkerRegistration->get_ActiveServiceWorker(&serviceWorker)); + + if (serviceWorker) + { + // Log that the service worker is activated. + } + else + { + CHECK_FAILURE(serviceWorkerRegistration->add_ServiceWorkerActivated( + Callback< + ICoreWebView2ExperimentalServiceWorkerActivatedEventHandler>( + [this]( + ICoreWebView2ExperimentalServiceWorkerRegistration* + sender, + ICoreWebView2ExperimentalServiceWorkerActivatedEventArgs* + args) -> HRESULT + { + wil::com_ptr + serviceWorker; + CHECK_FAILURE( + args->get_ActiveServiceWorker(&serviceWorker)); + + // Log that the service worker is activated. + m_appWindow->AsyncMessageBox( + L"Service worker is activated", L"Service worker"); + + return S_OK; + }) + .Get(), + nullptr)); + } + } + + return S_OK; + }) + .Get())); + } +} + +ScenarioServiceWorkerManager::~ScenarioServiceWorkerManager() +{ + if (m_serviceWorkerManager) + { + m_serviceWorkerManager->remove_ServiceWorkerRegistered(m_serviceWorkerRegisteredToken); + } +} diff --git a/SampleApps/WebView2APISample/ScenarioServiceWorkerManager.h b/SampleApps/WebView2APISample/ScenarioServiceWorkerManager.h new file mode 100644 index 00000000..2a47f533 --- /dev/null +++ b/SampleApps/WebView2APISample/ScenarioServiceWorkerManager.h @@ -0,0 +1,27 @@ +// 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 "AppWindow.h" +#include "ComponentBase.h" + +class ScenarioServiceWorkerManager : public ComponentBase +{ +public: + ScenarioServiceWorkerManager(AppWindow* appWindow); + ~ScenarioServiceWorkerManager() override; + + void GetAllServiceWorkerRegistrations(); + void GetServiceWorkerRegisteredForScope(); + +private: + void SetupEventsOnWebview(); + void CreateServiceWorkerManager(); + + AppWindow* m_appWindow; + wil::com_ptr m_webView; + wil::com_ptr m_serviceWorkerManager; + EventRegistrationToken m_serviceWorkerRegisteredToken = {}; +}; diff --git a/SampleApps/WebView2APISample/ScenarioServiceWorkerPostMessage.cpp b/SampleApps/WebView2APISample/ScenarioServiceWorkerPostMessage.cpp new file mode 100644 index 00000000..f592f540 --- /dev/null +++ b/SampleApps/WebView2APISample/ScenarioServiceWorkerPostMessage.cpp @@ -0,0 +1,168 @@ +// 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 "CheckFailure.h" + +#include "ScenarioServiceWorkerPostMessage.h" + +using namespace Microsoft::WRL; + +static constexpr WCHAR c_samplePath[] = L"scenario_sw_post_msg_scope/index.html"; + +ScenarioServiceWorkerPostMessage::ScenarioServiceWorkerPostMessage(AppWindow* appWindow) + : m_appWindow(appWindow), m_webView(appWindow->GetWebView()) +{ + CreateServiceWorkerManager(); + SetupEventsOnWebview(); +} + +void ScenarioServiceWorkerPostMessage::CreateServiceWorkerManager() +{ + auto webView2_13 = m_webView.try_query(); + CHECK_FEATURE_RETURN_EMPTY(webView2_13); + + wil::com_ptr webView2Profile; + CHECK_FAILURE(webView2_13->get_Profile(&webView2Profile)); + auto webViewExperimentalProfile13 = + webView2Profile.try_query(); + CHECK_FEATURE_RETURN_EMPTY(webViewExperimentalProfile13); + CHECK_FAILURE( + webViewExperimentalProfile13->get_ServiceWorkerManager(&m_serviceWorkerManager)); +} + +void ScenarioServiceWorkerPostMessage::SetupEventsOnWebview() +{ + if (!m_serviceWorkerManager) + { + return; + } + + CHECK_FAILURE(m_serviceWorkerManager->add_ServiceWorkerRegistered( + Callback( + [this]( + ICoreWebView2ExperimentalServiceWorkerManager* sender, + ICoreWebView2ExperimentalServiceWorkerRegisteredEventArgs* args) + { + wil::com_ptr + serviceWorkerRegistration; + CHECK_FAILURE(args->get_ServiceWorkerRegistration(&serviceWorkerRegistration)); + + if (serviceWorkerRegistration) + { + wil::unique_cotaskmem_string scopeUri; + CHECK_FAILURE(serviceWorkerRegistration->get_ScopeUri(&scopeUri)); + std::wstring scopeUriStr(scopeUri.get()); + + wil::com_ptr serviceWorker; + CHECK_FAILURE( + serviceWorkerRegistration->get_ActiveServiceWorker(&serviceWorker)); + + if (serviceWorker) + { + SetupEventsOnServiceWorker(serviceWorker); + AddToCache(L"img.jpg", serviceWorker); + } + else + { + CHECK_FAILURE(serviceWorkerRegistration->add_ServiceWorkerActivated( + Callback< + ICoreWebView2ExperimentalServiceWorkerActivatedEventHandler>( + [this]( + ICoreWebView2ExperimentalServiceWorkerRegistration* sender, + ICoreWebView2ExperimentalServiceWorkerActivatedEventArgs* + args) -> HRESULT + { + wil::com_ptr + serviceWorker; + CHECK_FAILURE( + args->get_ActiveServiceWorker(&serviceWorker)); + + SetupEventsOnServiceWorker(serviceWorker); + AddToCache(L"img.jpg", serviceWorker); + + return S_OK; + }) + .Get(), + nullptr)); + } + + m_appWindow->AsyncMessageBox(scopeUriStr, L"Service worker is registered"); + } + + return S_OK; + }) + .Get(), + &m_serviceWorkerRegisteredToken)); + + // Turn off this scenario if we navigate away from the sample page. + 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)); + + m_sampleUri = m_appWindow->GetLocalUri(c_samplePath); + CHECK_FAILURE(m_webView->Navigate(m_sampleUri.c_str())); +} + +void ScenarioServiceWorkerPostMessage::SetupEventsOnServiceWorker( + wil::com_ptr serviceWorker) +{ + //! [WebMessageReceived] + serviceWorker->add_WebMessageReceived( + Callback( + [this]( + ICoreWebView2ExperimentalServiceWorker* sender, + ICoreWebView2WebMessageReceivedEventArgs* args) -> HRESULT + { + wil::unique_cotaskmem_string scriptUri; + CHECK_FAILURE(args->get_Source(&scriptUri)); + + wil::unique_cotaskmem_string messageRaw; + CHECK_FAILURE(args->TryGetWebMessageAsString(&messageRaw)); + std::wstring messageFromWorker = messageRaw.get(); + + std::wstringstream message{}; + message << L"Service Worker: " << std::endl << scriptUri.get() << std::endl; + message << std::endl; + message << L"Message: " << std::endl << messageFromWorker << std::endl; + m_appWindow->AsyncMessageBox(message.str(), L"Message from Service Worker"); + + return S_OK; + }) + .Get(), + nullptr); + //! [WebMessageReceived] +} + +void ScenarioServiceWorkerPostMessage::AddToCache( + std::wstring url, wil::com_ptr serviceWorker) +{ + //! [PostWebMessageAsJson] + std::wstring msg = L"{\"command\":\"ADD_TO_CACHE\",\"url\":\"" + url + L"\"}"; + serviceWorker->PostWebMessageAsJson(msg.c_str()); + //! [PostWebMessageAsJson] +} + +ScenarioServiceWorkerPostMessage::~ScenarioServiceWorkerPostMessage() +{ + if (m_serviceWorkerManager) + { + m_serviceWorkerManager->remove_ServiceWorkerRegistered(m_serviceWorkerRegisteredToken); + } + + m_webView->remove_ContentLoading(m_contentLoadingToken); +} diff --git a/SampleApps/WebView2APISample/ScenarioServiceWorkerPostMessage.h b/SampleApps/WebView2APISample/ScenarioServiceWorkerPostMessage.h new file mode 100644 index 00000000..2c83d25d --- /dev/null +++ b/SampleApps/WebView2APISample/ScenarioServiceWorkerPostMessage.h @@ -0,0 +1,30 @@ +// 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 "AppWindow.h" +#include "ComponentBase.h" + +class ScenarioServiceWorkerPostMessage : public ComponentBase +{ +public: + ScenarioServiceWorkerPostMessage(AppWindow* appWindow); + ~ScenarioServiceWorkerPostMessage() override; + +private: + void SetupEventsOnWebview(); + void CreateServiceWorkerManager(); + void SetupEventsOnServiceWorker( + wil::com_ptr serviceWorker); + void AddToCache( + std::wstring url, wil::com_ptr serviceWorker); + + AppWindow* m_appWindow; + wil::com_ptr m_webView; + std::wstring m_sampleUri; + wil::com_ptr m_serviceWorkerManager; + EventRegistrationToken m_contentLoadingToken = {}; + EventRegistrationToken m_serviceWorkerRegisteredToken = {}; +}; diff --git a/SampleApps/WebView2APISample/ScenarioSharedWorkerManager.cpp b/SampleApps/WebView2APISample/ScenarioSharedWorkerManager.cpp new file mode 100644 index 00000000..0d682155 --- /dev/null +++ b/SampleApps/WebView2APISample/ScenarioSharedWorkerManager.cpp @@ -0,0 +1,132 @@ +// 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 "CheckFailure.h" + +#include "ScenarioSharedWorkerManager.h" + +using namespace Microsoft::WRL; + +ScenarioSharedWorkerManager::ScenarioSharedWorkerManager(AppWindow* appWindow) + : m_appWindow(appWindow), m_webView(appWindow->GetWebView()) +{ + GetSharedWorkerManager(); + SetupEventsOnWebview(); +} + +void ScenarioSharedWorkerManager::GetSharedWorkerManager() +{ + //! [SharedWorkerManager] + auto webView2_13 = m_webView.try_query(); + CHECK_FEATURE_RETURN_EMPTY(webView2_13); + + wil::com_ptr webView2Profile; + CHECK_FAILURE(webView2_13->get_Profile(&webView2Profile)); + auto webViewExperimentalProfile13 = + webView2Profile.try_query(); + CHECK_FEATURE_RETURN_EMPTY(webViewExperimentalProfile13); + CHECK_FAILURE( + webViewExperimentalProfile13->get_SharedWorkerManager(&m_sharedWorkerManager)); + //! [SharedWorkerManager] +} + +void ScenarioSharedWorkerManager::SetupEventsOnWebview() +{ + if (!m_sharedWorkerManager) + { + return; + } + + //! [SharedWorkerCreated] + CHECK_FAILURE(m_sharedWorkerManager->add_SharedWorkerCreated( + Callback( + [this]( + ICoreWebView2ExperimentalSharedWorkerManager* sender, + ICoreWebView2ExperimentalSharedWorkerCreatedEventArgs* args) + { + wil::com_ptr sharedWorker; + CHECK_FAILURE(args->get_Worker(&sharedWorker)); + + wil::unique_cotaskmem_string scriptUri; + CHECK_FAILURE(sharedWorker->get_ScriptUri(&scriptUri)); + + std::wstring scriptUriStr(scriptUri.get()); + m_appWindow->AsyncMessageBox(scriptUriStr, L"Shared worker is created"); + + // Subscribe to worker destroying event + sharedWorker->add_Destroying( + Callback( + [this, scriptUriStr]( + ICoreWebView2ExperimentalSharedWorker* sender, + IUnknown* args) -> HRESULT + { + /*Cleanup on worker destruction*/ + m_appWindow->AsyncMessageBox( + scriptUriStr, L"Shared worker is destroyed"); + return S_OK; + }) + .Get(), + nullptr); + + return S_OK; + }) + .Get(), + &m_sharedWorkerCreatedToken)); + //! [SharedWorkerCreated] +} + +void ScenarioSharedWorkerManager::GetAllSharedWorkers() +{ + CHECK_FEATURE_RETURN_EMPTY(m_sharedWorkerManager); + CHECK_FAILURE(m_sharedWorkerManager->GetSharedWorkers( + Callback( + [this]( + HRESULT error, + ICoreWebView2ExperimentalSharedWorkerCollectionView* workersCollection) + -> HRESULT + { + UINT32 workersCount = 0; + CHECK_FAILURE(workersCollection->get_Count(&workersCount)); + + std::wstringstream message{}; + message << L"Number of shared workers created: " << workersCount << std::endl; + + for (UINT32 i = 0; i < workersCount; i++) + { + ComPtr sharedWorker; + CHECK_FAILURE(workersCollection->GetValueAtIndex(i, &sharedWorker)); + + wil::unique_cotaskmem_string scriptUri; + CHECK_FAILURE(sharedWorker->get_ScriptUri(&scriptUri)); + + wil::unique_cotaskmem_string origin; + CHECK_FAILURE(sharedWorker->get_Origin(&origin)); + + wil::unique_cotaskmem_string topLevelOrigin; + CHECK_FAILURE(sharedWorker->get_TopLevelOrigin(&topLevelOrigin)); + + message << L"ScriptUri: " << scriptUri.get(); + message << L" Origin: " << origin.get(); + message << L" TopLevelOrigin: " << topLevelOrigin.get(); + message << std::endl; + } + + m_appWindow->AsyncMessageBox( + std::move(message.str()), L"Get all shared workers"); + + return S_OK; + }) + .Get())); +} + +ScenarioSharedWorkerManager::~ScenarioSharedWorkerManager() +{ + if (m_sharedWorkerManager) + { + m_sharedWorkerManager->remove_SharedWorkerCreated(m_sharedWorkerCreatedToken); + } +} diff --git a/SampleApps/WebView2APISample/ScenarioSharedWorkerManager.h b/SampleApps/WebView2APISample/ScenarioSharedWorkerManager.h new file mode 100644 index 00000000..021d11dd --- /dev/null +++ b/SampleApps/WebView2APISample/ScenarioSharedWorkerManager.h @@ -0,0 +1,26 @@ +// 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 "AppWindow.h" +#include "ComponentBase.h" + +class ScenarioSharedWorkerManager : public ComponentBase +{ +public: + ScenarioSharedWorkerManager(AppWindow* appWindow); + ~ScenarioSharedWorkerManager() override; + + void GetAllSharedWorkers(); + +private: + void SetupEventsOnWebview(); + void GetSharedWorkerManager(); + + AppWindow* m_appWindow; + wil::com_ptr m_webView; + wil::com_ptr m_sharedWorkerManager; + EventRegistrationToken m_sharedWorkerCreatedToken = {}; +}; diff --git a/SampleApps/WebView2APISample/ScenarioWindowControlsOverlay.cpp b/SampleApps/WebView2APISample/ScenarioWindowControlsOverlay.cpp new file mode 100644 index 00000000..6d2e3a8e --- /dev/null +++ b/SampleApps/WebView2APISample/ScenarioWindowControlsOverlay.cpp @@ -0,0 +1,25 @@ +#include "stdafx.h" + +#include "AppWindow.h" +#include "CheckFailure.h" +#include "ScenarioWindowControlsOverlay.h" +#include + +using namespace Microsoft::WRL; +using namespace std; + +static constexpr wchar_t c_samplePath[] = L"ScenarioWindowControlsOverlay.html"; + +ScenarioWindowControlsOverlay::ScenarioWindowControlsOverlay(AppWindow* appWindow) +{ + //! [WindowControlsOverlay] + std::wstring sampleUri = appWindow->GetLocalUri(c_samplePath); + WebViewCreateOption options = appWindow->GetWebViewOption(); + options.useWco = true; + AppWindow* appWindowWco = new AppWindow(appWindow->GetCreationModeId(), options, sampleUri); + //! [WindowControlsOverlay] +} + +ScenarioWindowControlsOverlay::~ScenarioWindowControlsOverlay() +{ +} diff --git a/SampleApps/WebView2APISample/ScenarioWindowControlsOverlay.h b/SampleApps/WebView2APISample/ScenarioWindowControlsOverlay.h new file mode 100644 index 00000000..4b82e90d --- /dev/null +++ b/SampleApps/WebView2APISample/ScenarioWindowControlsOverlay.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 ScenarioWindowControlsOverlay : public ComponentBase +{ +public: + ScenarioWindowControlsOverlay(AppWindow* appWindow); + ~ScenarioWindowControlsOverlay() override; +}; diff --git a/SampleApps/WebView2APISample/WebView2APISample.rc b/SampleApps/WebView2APISample/WebView2APISample.rc index 0d2804b6..399acbe8 100644 --- a/SampleApps/WebView2APISample/WebView2APISample.rc +++ b/SampleApps/WebView2APISample/WebView2APISample.rc @@ -296,6 +296,8 @@ BEGIN MENUITEM "Virtual Host Mapping For Pop Up Window", IDM_SCENARIO_VIRTUAL_HOST_MAPPING_POP_UP_WINDOW MENUITEM "Web Messaging", IDM_SCENARIO_POST_WEB_MESSAGE MENUITEM "WebView Event Monitor", IDM_SCENARIO_WEB_VIEW_EVENT_MONITOR + MENUITEM "WebView Window Controls Overlay", IDM_SCENARIO_WINDOW_CONTROLS_OVERLAY + MENUITEM "Dropped file path", IDM_SCENARIO_DROPPED_FILE_PATH POPUP "Save As" BEGIN @@ -306,6 +308,23 @@ 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 "Service Worker" + BEGIN + MENUITEM "Listen to new Service Worker Registrations", IDM_SCENARIO_SERVICE_WORKER_REGISTRATION_REQUESTED + MENUITEM "Get Service Worker Registrations", IDM_SCENARIO_GET_SERVICE_WORKER_REGISTRATIONS + MENUITEM "Get Service Worker registered for the Scope", IDM_SCENARIO_GET_SERVICE_WORKER_REGISTERED_FOR_SCOPE + MENUITEM "Web Messaging", IDM_SCENARIO_SERVICE_WORKER_POST_MESSAGE + END + POPUP "Dedicated Worker" + BEGIN + MENUITEM "Listen to new Dedicated Worker Creations", IDM_SCENARIO_DEDICATED_WORKER + MENUITEM "Web Messaging", IDM_SCENARIO_DEDICATED_WORKER_POST_MESSAGE + END + POPUP "Shared Worker" + BEGIN + MENUITEM "Listen to new Shared Worker Creations", IDM_SCENARIO_SHARED_WORKER_MANAGER + MENUITEM "Get Shared Workers", IDM_SCENARIO_GET_SHARED_WORKERS + END POPUP "Start Find" BEGIN MENUITEM "Start Find on Page Dialog", IDM_START_FIND diff --git a/SampleApps/WebView2APISample/WebView2APISample.vcxproj b/SampleApps/WebView2APISample/WebView2APISample.vcxproj index 28b46021..0e916d67 100644 --- a/SampleApps/WebView2APISample/WebView2APISample.vcxproj +++ b/SampleApps/WebView2APISample/WebView2APISample.vcxproj @@ -234,6 +234,8 @@ + + @@ -248,13 +250,17 @@ + + + + @@ -289,6 +295,8 @@ + + @@ -303,13 +311,17 @@ + + + + @@ -431,6 +443,9 @@ $(OutDir)\assets + + $(OutDir)\assets + $(OutDir)\assets @@ -502,13 +517,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/ScenarioWindowControlsOverlay.html b/SampleApps/WebView2APISample/assets/ScenarioWindowControlsOverlay.html new file mode 100644 index 00000000..dfc14e67 --- /dev/null +++ b/SampleApps/WebView2APISample/assets/ScenarioWindowControlsOverlay.html @@ -0,0 +1,11 @@ + + + + + + Webview2 Window Controls Overlay + + +

Window Controls overlay

+ + \ No newline at end of file diff --git a/SampleApps/WebView2APISample/assets/dedicated_worker.js b/SampleApps/WebView2APISample/assets/dedicated_worker.js index f19caa78..d7ef8e48 100644 --- a/SampleApps/WebView2APISample/assets/dedicated_worker.js +++ b/SampleApps/WebView2APISample/assets/dedicated_worker.js @@ -1,6 +1,7 @@ //! [chromeWebView] self.chrome.webview.addEventListener('message', (e) => { const data = e.data; + e.source.postMessage('Received msg :' + JSON.stringify(data)); if (!data.hasOwnProperty('first') || !data.hasOwnProperty('second') || !data.hasOwnProperty('command')) { return; diff --git a/SampleApps/WebView2APISample/packages.config b/SampleApps/WebView2APISample/packages.config index e769b55b..c8fcd36b 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 a2154c39..61a08d9b 100644 --- a/SampleApps/WebView2APISample/resource.h +++ b/SampleApps/WebView2APISample/resource.h @@ -193,6 +193,13 @@ #define IDM_GET_MATCHES 2047 #define IDM_GET_ACTIVE_MATCH_INDEX 2048 #define IDM_SCENARIO_FILE_TYPE_POLICY 2049 +#define IDM_SCENARIO_SERVICE_WORKER_REGISTRATION_REQUESTED 2050 +#define IDM_SCENARIO_DEDICATED_WORKER 2051 +#define IDM_SCENARIO_SHARED_WORKER_MANAGER 2052 +#define IDM_SCENARIO_GET_SERVICE_WORKER_REGISTRATIONS 2053 +#define IDM_SCENARIO_GET_SERVICE_WORKER_REGISTERED_FOR_SCOPE 2054 +#define IDM_SCENARIO_GET_SHARED_WORKERS 2055 +#define IDM_SCENARIO_WINDOW_CONTROLS_OVERLAY 2057 #define IDC_FIND_TERM 2059 #define IDC_IS_CASE_SENSITIVE 2060 #define IDC_SHOULD_MATCH_WHOLE_WORD 2061 @@ -203,6 +210,8 @@ #define IDM_CREATION_MODE_TARGET_DCOMP 3002 #define IDM_CREATION_MODE_VISUAL_WINCOMP 3003 #define IDM_CREATION_MODE_HOST_INPUT_PROCESSING 3006 +#define IDM_SCENARIO_DEDICATED_WORKER_POST_MESSAGE 3009 +#define IDM_SCENARIO_SERVICE_WORKER_POST_MESSAGE 3010 #define ID_BLOCKEDSITES 32773 #define ID_SETTINGS_NAVIGATETOSTRING 32774 #define ID_ADD_INITIALIZE_SCRIPT 32775 diff --git a/SampleApps/WebView2WindowsFormsBrowser/WebView2WindowsFormsBrowser.csproj b/SampleApps/WebView2WindowsFormsBrowser/WebView2WindowsFormsBrowser.csproj index 91be9ce0..c5af8394 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 0b46fca0..e20f7281 100644 --- a/SampleApps/WebView2WpfBrowser/MainWindow.xaml +++ b/SampleApps/WebView2WpfBrowser/MainWindow.xaml @@ -107,6 +107,16 @@ found in the LICENSE file. + + + + + + + + + + diff --git a/SampleApps/WebView2WpfBrowser/MainWindow.xaml.cs b/SampleApps/WebView2WpfBrowser/MainWindow.xaml.cs index 525aade6..ff35fd35 100644 --- a/SampleApps/WebView2WpfBrowser/MainWindow.xaml.cs +++ b/SampleApps/WebView2WpfBrowser/MainWindow.xaml.cs @@ -3834,17 +3834,111 @@ void DedicatedWorkerCreatedExecuted(object target, ExecutedRoutedEventArgs e) void RegisterForDedicatedWorkerCreated() { +#if USE_WEBVIEW2_EXPERIMENTAL + _iWebView2.CoreWebView2.DedicatedWorkerCreated += (sender, args) => + { + CoreWebView2DedicatedWorker dedicatedWorker = args.Worker; + MessageBox.Show("Dedicated worker is created" , "Dedicated Worker Message"); + }; +#endif } + +#if USE_WEBVIEW2_EXPERIMENTAL +private string _dedicatedWorkerPostMessageStr; +#endif + void DedicatedWorkerPostMessageExecuted(object target, ExecutedRoutedEventArgs e) { +#if USE_WEBVIEW2_EXPERIMENTAL + _iWebView2.CoreWebView2.DedicatedWorkerCreated += DedicatedWorker_PostMessage_DedicatedWorkerCreated; + _iWebView2.CoreWebView2.DOMContentLoaded += DedicatedWorker_PostMessage_DOMContentLoaded; + + var dialog = new TextInputDialog( + title: "Post Web Message JSON", + description: "Enter the web message as JSON.", + defaultInput: "{\"command\":\"ADD\",\"first\":2,\"second\":3}"); + // Ex: {"command":"MUL","first":2,"second":3} + if (dialog.ShowDialog() == true) + { + _dedicatedWorkerPostMessageStr = dialog.Input.Text; + } + + _iWebView2.CoreWebView2.Navigate("https://appassets.example/ScenarioDedicatedWorkerPostMessage.html"); +#endif } + +#if USE_WEBVIEW2_EXPERIMENTAL + void DedicatedWorker_PostMessage_DedicatedWorkerCreated(object sender, CoreWebView2DedicatedWorkerCreatedEventArgs args) + { + CoreWebView2DedicatedWorker dedicatedWorker = args.Worker; + MessageBox.Show("Dedicated worker is created" , "Dedicated Worker Message"); + DedicatedWorker_PostMessage_SetupEventsOnDedicatedWorker(dedicatedWorker); + DedicatedWorker_PostMessage_ComputeWithDedicatedWorker(dedicatedWorker); + } + + void DedicatedWorker_PostMessage_DOMContentLoaded(object sender, CoreWebView2DOMContentLoadedEventArgs dedicatedWorker) + { + // Turn off this scenario if we navigate away from the sample page. + if (_iWebView2.CoreWebView2.Source != "https://appassets.example/ScenarioDedicatedWorkerPostMessage.html") + { + _iWebView2.CoreWebView2.DedicatedWorkerCreated -= DedicatedWorker_PostMessage_DedicatedWorkerCreated; + _iWebView2.CoreWebView2.DOMContentLoaded -= DedicatedWorker_PostMessage_DOMContentLoaded; + } + } + + void DedicatedWorker_PostMessage_SetupEventsOnDedicatedWorker(CoreWebView2DedicatedWorker dedicatedWorker) + { + dedicatedWorker.WebMessageReceived += (sender, args) => + { + StringBuilder messageBuilder = new StringBuilder(); + messageBuilder.AppendLine($"Dedicated Worker: \n{args.Source} "); + messageBuilder.AppendLine($"\nMessage: \n{args.TryGetWebMessageAsString()} "); + MessageBox.Show(messageBuilder.ToString(), "Message from Dedicated Worker", MessageBoxButton.OK); + }; + } + + void DedicatedWorker_PostMessage_ComputeWithDedicatedWorker(CoreWebView2DedicatedWorker dedicatedWorker) + { + dedicatedWorker.PostWebMessageAsJson(_dedicatedWorkerPostMessageStr); + } +#endif + +#if USE_WEBVIEW2_EXPERIMENTAL + CoreWebView2ServiceWorkerManager ServiceWorkerManager_; +#endif void ServiceWorkerRegisteredExecuted(object target, ExecutedRoutedEventArgs e) { RegisterForServiceWorkerRegistered(); } + void RegisterForServiceWorkerRegistered() { +#if USE_WEBVIEW2_EXPERIMENTAL + if (ServiceWorkerManager_ == null) + { + ServiceWorkerManager_ = WebViewProfile.ServiceWorkerManager; + } + ServiceWorkerManager_.ServiceWorkerRegistered += (sender, args) => + { + CoreWebView2ServiceWorkerRegistration serviceWorkerRegistration = args.ServiceWorkerRegistration; + MessageBox.Show("Service worker is registered for " + serviceWorkerRegistration.ScopeUri, "Service Worker Registration Message"); + + CoreWebView2ServiceWorker serviceWorker = serviceWorkerRegistration.ActiveServiceWorker; + if (serviceWorker != null) + { + MessageBox.Show("Service worker is created.", "Service Worker Message"); + } + else + { + serviceWorkerRegistration.ServiceWorkerActivated += (sender1, args1) => + { + MessageBox.Show("Service worker is created.", "Service Worker Message"); + }; + } + }; +#endif } + private void GetServiceWorkerRegistrationsExecuted(object target, ExecutedRoutedEventArgs e) { GetServiceWorkerRegistrations(); @@ -3852,7 +3946,35 @@ private void GetServiceWorkerRegistrationsExecuted(object target, ExecutedRouted async void GetServiceWorkerRegistrations() { +#if USE_WEBVIEW2_EXPERIMENTAL + try + { + if (ServiceWorkerManager_ == null) + { + ServiceWorkerManager_ = WebViewProfile.ServiceWorkerManager; + } + IReadOnlyList registrationList = await ServiceWorkerManager_.GetServiceWorkerRegistrationsAsync(); + int registrationCount = registrationList.Count; + StringBuilder messageBuilder = new StringBuilder(); + messageBuilder.AppendLine($"No of service workers registered: {registrationCount}"); + + for (int i = 0; i < registrationList.Count(); ++i) + { + var scopeUri = registrationList[i].ScopeUri; + + messageBuilder.AppendLine($"Scope: {scopeUri}"); + }; + + MessageBox.Show(messageBuilder.ToString(), "Service Worker Registrations", MessageBoxButton.OK); + } + catch (NotImplementedException exception) + { + MessageBox.Show(this, "GetServiceWorkerRegistrationsAsync Failed: " + exception.Message, + "Get Service Worker Registrations Info"); + } +#else await Task.Delay(0); +#endif } void GetServiceWorkerRegisteredForScopeExecuted(object target, ExecutedRoutedEventArgs e) @@ -3862,19 +3984,131 @@ void GetServiceWorkerRegisteredForScopeExecuted(object target, ExecutedRoutedEve async void GetServiceWorkerRegisteredForScope() { +#if USE_WEBVIEW2_EXPERIMENTAL + var dialog = new TextInputDialog( + title: "Scope of the Service Worker Registration", + description: "Specify a scope to get the service worker", + defaultInput: ""); + if (dialog.ShowDialog() == true) + { + try + { + if (ServiceWorkerManager_ == null) + { + ServiceWorkerManager_ = WebViewProfile.ServiceWorkerManager; + } + IReadOnlyList registrationList = await ServiceWorkerManager_.GetServiceWorkerRegistrationsAsync(dialog.Input.Text); + + for (int i = 0; i < registrationList.Count(); ++i) + { + CoreWebView2ServiceWorker worker = registrationList[i].ActiveServiceWorker; + + }; + + MessageBox.Show("Number of service workers registered for the given scope: " + (registrationList.Count()).ToString() + , "Service Worker Registrations", MessageBoxButton.OK); + } + catch (NotImplementedException exception) + { + MessageBox.Show(this, "GetServiceWorkerRegistrationsAsync Failed: " + exception.Message, + "Get Service Workers Info"); + } + } +#else await Task.Delay(0); +#endif } +#if USE_WEBVIEW2_EXPERIMENTAL + CoreWebView2ServiceWorkerManager PostMessage_ServiceWorkerManager_; +#endif + void ServiceWorkerPostMessageExecuted(object target, ExecutedRoutedEventArgs e) { +#if USE_WEBVIEW2_EXPERIMENTAL + PostMessage_ServiceWorkerManager_ = WebViewProfile.ServiceWorkerManager; + + PostMessage_ServiceWorkerManager_.ServiceWorkerRegistered += ServiceWorker_PostMessage_ServiceWorkerRegistered; + _iWebView2.CoreWebView2.DOMContentLoaded += ServiceWorker_PostMessage_DOMContentLoaded; + + _iWebView2.CoreWebView2.Navigate("https://appassets.example/scenario_sw_post_msg_scope/index.html"); +#endif + } + +#if USE_WEBVIEW2_EXPERIMENTAL + void ServiceWorker_PostMessage_ServiceWorkerRegistered(object sender, CoreWebView2ServiceWorkerRegisteredEventArgs args) + { + CoreWebView2ServiceWorkerRegistration serviceWorkerRegistration = args.ServiceWorkerRegistration; + MessageBox.Show("Service worker is registered for " + serviceWorkerRegistration.ScopeUri, "Service Worker Registration Message"); + + CoreWebView2ServiceWorker serviceWorker = serviceWorkerRegistration.ActiveServiceWorker; + if (serviceWorker != null) + { + ServiceWorker_PostMessage_SetupEventsOnServiceWorker(serviceWorker); + ServiceWorker_PostMessage_AddToCache(serviceWorker, "img.jpg"); + } + else + { + serviceWorkerRegistration.ServiceWorkerActivated += (sender1, args1) => + { + ServiceWorker_PostMessage_SetupEventsOnServiceWorker(serviceWorker); + ServiceWorker_PostMessage_AddToCache(serviceWorker, "img.jpg"); + }; + } + } + + void ServiceWorker_PostMessage_DOMContentLoaded(object sender, CoreWebView2DOMContentLoadedEventArgs dedicatedWorker) + { + // Turn off this scenario if we navigate away from the sample page. + if (_iWebView2.CoreWebView2.Source != "https://appassets.example/scenario_sw_post_msg_scope/index.html") + { + PostMessage_ServiceWorkerManager_.ServiceWorkerRegistered -= ServiceWorker_PostMessage_ServiceWorkerRegistered; + _iWebView2.CoreWebView2.DOMContentLoaded -= ServiceWorker_PostMessage_DOMContentLoaded; + PostMessage_ServiceWorkerManager_ = null; + } + } + + void ServiceWorker_PostMessage_SetupEventsOnServiceWorker(CoreWebView2ServiceWorker serviceWorker) + { + serviceWorker.WebMessageReceived += (sender, args) => + { + StringBuilder messageBuilder = new StringBuilder(); + messageBuilder.AppendLine($"Service Worker: \n{args.Source} "); + messageBuilder.AppendLine($"\nMessage: \n{args.TryGetWebMessageAsString()} "); + MessageBox.Show(messageBuilder.ToString(), "Message from Service Worker", MessageBoxButton.OK); + }; } + + void ServiceWorker_PostMessage_AddToCache(CoreWebView2ServiceWorker serviceWorker, string url) + { + string msg = "{\"command\":\"ADD_TO_CACHE\",\"url\":\"" + url + "\"}"; + serviceWorker.PostWebMessageAsJson(msg); + } +#endif + +#if USE_WEBVIEW2_EXPERIMENTAL + CoreWebView2SharedWorkerManager SharedWorkerManager_; +#endif void SharedWorkerManagerExecuted(object target, ExecutedRoutedEventArgs e) { RegisterForSharedWorkerCreated(); } + void RegisterForSharedWorkerCreated() { +#if USE_WEBVIEW2_EXPERIMENTAL + if (SharedWorkerManager_ == null) + { + SharedWorkerManager_ = WebViewProfile.SharedWorkerManager; + } + SharedWorkerManager_.SharedWorkerCreated += (sender, args) => + { + CoreWebView2SharedWorker sharedWorker = args.Worker; + MessageBox.Show("Shared worker is created", "Shared Worker Message"); + }; +#endif } + private void GetSharedWorkersExecuted(object target, ExecutedRoutedEventArgs e) { GetSharedWorkers(); @@ -3882,7 +4116,28 @@ private void GetSharedWorkersExecuted(object target, ExecutedRoutedEventArgs e) async void GetSharedWorkers() { +#if USE_WEBVIEW2_EXPERIMENTAL + try + { + if (SharedWorkerManager_ == null) + { + SharedWorkerManager_ = WebViewProfile.SharedWorkerManager; + } + IReadOnlyList workerList = await SharedWorkerManager_.GetSharedWorkersAsync(); + int workerCount = workerList.Count; + StringBuilder messageBuilder = new StringBuilder(); + messageBuilder.AppendLine($"No of shared workers created: {workerCount}"); + + MessageBox.Show(messageBuilder.ToString(), "Shared Workers", MessageBoxButton.OK); + } + catch (NotImplementedException exception) + { + MessageBox.Show(this, "GetSharedWorkersAsync Failed: " + exception.Message, + "Get Shared Workers Info"); + } +#else await Task.Delay(0); +#endif } async void ServiceWorkerSyncManagerExecuted(object target, ExecutedRoutedEventArgs e) { diff --git a/SampleApps/WebView2WpfBrowser/WebView2WpfBrowser.csproj b/SampleApps/WebView2WpfBrowser/WebView2WpfBrowser.csproj index c156f075..22cf026b 100644 --- a/SampleApps/WebView2WpfBrowser/WebView2WpfBrowser.csproj +++ b/SampleApps/WebView2WpfBrowser/WebView2WpfBrowser.csproj @@ -61,7 +61,7 @@ - +