diff --git a/specs/MultiProfile.md b/specs/MultiProfile.md index 14ae95c32..7c79f61b4 100644 --- a/specs/MultiProfile.md +++ b/specs/MultiProfile.md @@ -169,20 +169,42 @@ void ScenarioCookieManagement::DeleteAllCookies() ### Delete profile ```cpp -HRESULT AppWindow::DeleteProfile(ICoreWebView2Controller* controller) +HRESULT AppWindow::DeleteProfile(ICoreWebView2* webView2) { - wil::com_ptr coreWebView2; - CHECK_FAILURE(controller->get_CoreWebView2(&coreWebView2)); - auto webview7 = coreWebView2.try_query(); - if (webview7) - { - wil::com_ptr profile; - CHECK_FAILURE(webview7->get_Profile(&profile)); - auto profile2 = profile.try_query(); - if (profile2) - { - CHECK_FAILURE(profile2->Delete()); - } + wil::com_ptr profile; + CHECK_FAILURE(webView2->get_Profile(&profile)); + CHECK_FAILURE(profile2->Delete()); +} + +void AppWindow::RegisterEventHandlers() +{ + BOOL isWebview2Closed = FALSE; + CHECK_FAILURE(webView2->get_IsClosed(&isWebview2Closed)); + if (!isWebview2Closed) { + CHECK_FAILURE(m_webView->add_Closed( + Microsoft::WRL::Callback( + [this](ICoreWebView2_20* sender, ICoreWebView2EventArgs* args) + { + COREWEBVIEW2_CLOSED_REASON reason; + CHECK_FAILURE(args->get_Reason(&reason)); + std::wstring message; + switch (reason) + { + case COREWEBVIEW2_CLOSED_REASON::COREWEBVIEW2_CLOSED_REASON_PROFILE_DELETED: + { + message = L"The CoreWebView2 has closed because its corresponding " + L"Profile has been or marked as deleted."; + break; + } + } + RunAsync([this, message]() + { + MessageBox( + m_mainWindow, message.c_str(), L"webview2 closed", MB_OK); + CloseAppWindow(); + }); + return S_OK; + }).Get(), nullptr)); } } ``` @@ -253,10 +275,36 @@ public DeleteProfile(CoreWebView2Controller controller) { // Get the profile object. CoreWebView2Profile profile = controller.CoreWebView2.Profile; - + // Delete current profile. profile.Delete(); } + +void WebView_CoreWebView2InitializationCompleted(object sender, CoreWebView2InitializationCompletedEventArgs e) +{ + if (!webView.IsClosed) { + webView.CoreWebView2.Closed += CoreWebView2_Closed; + } +} + +private void CoreWebView2_Closed(object sender, CoreWebView2ClosedEventArgs e) +{ + String message; + switch (e.Reason) + { + case CoreWebView2ClosedReason.ProfileDeleted: + { + message = "The CoreWebView2 has closed because its corresponding Profile has been or marked as deleted." + break; + } + } + + this.Dispatcher.InvokeAsync(() => + { + MessageBox.Show(message); + Close(); + }); +} ``` # API Details @@ -267,9 +315,13 @@ public DeleteProfile(CoreWebView2Controller controller) interface ICoreWebView2ControllerOptions; interface ICoreWebView2Environment5; interface ICoreWebView2_7; +interface ICoreWebView2_9; interface ICoreWebView2Profile; interface ICoreWebView2Profile2; interface ICoreWebView2Profile3; +interface ICoreWebView2Profile4; +interface ICoreWebView2ClosedEventHandler; +interface ICoreWebView2ClosedEventArgs; /// This interface is used to manage profile options that created by 'CreateCoreWebView2ControllerOptions'. [uuid(C2669A3A-03A9-45E9-97EA-03CD55E5DC03), object, pointer_default(unique)] @@ -363,17 +415,65 @@ interface ICoreWebView2Profile2 : ICoreWebView2Profile { [propget] HRESULT CookieManager([out, retval] ICoreWebView2CookieManager** cookieManager); } -[uuid(1c1ae2cc-d5c2-ffe3-d3e7-7857035d23b7), object, pointer_default(unique)] -interface ICoreWebView2Profile3 : ICoreWebView2Profile2 { - /// All webviews on this profile will be closed, and the profile will be marked for deletion. - /// After the Delete() call completes, The render process of webviews on this profile will - /// asynchronously exit with the reason:`COREWEBVIEW2_PROCESS_FAILED_REASON_PROFILE_DELETED`. - /// See 'COREWEBVIEW2_PROCESS_FAILED_REASON::COREWEBVIEW2_PROCESS_FAILED_REASON_PROFILE_DELETED' - /// for more details. The profile directory on disk will be actually deleted when the browser - /// process exits. Webview2 creation will fail with the HRESULT is ERROR_INVALID_STATE(0x8007139FL) - /// if you create it with the same name as a profile that is being deleted. - HRESULT Delete(); +[uuid(2765B8BD-7C57-4B76-B8AA-1EC940FE92CC), object, pointer_default(unique)] +interface ICoreWebView2Profile4 : IUnknown { + /// After the API is called, the profile will be marked for deletion. The + /// local profile's directory will be tried to delete at browser process + /// exit, if fail to delete, it will recursively try to delete at next + /// browser process start until successful. + /// The corresponding webview2s will be auto closed and its Closed event + /// handle function will be triggered with the reason is + /// COREWEBVIEW2_CLOSED_REASON.COREWEBVIEW2_CLOSED_REASON_PROFILE_DELETED. + /// If create a new profile with the same name as the profile that has been + /// marked as deleted will be failure with the HRESULT:ERROR_INVALID_STATE + /// (0x8007139FL). + HRESULT Delete(); +} + +[uuid(cc39bea3-f6f8-471b-919f-fa253e2fff03), object, pointer_default(unique)] +interface ICoreWebView2_9 : IUnknown { + /// Add an event handler for the `Closed` event. `Closed` enent handle runs + /// when the webview2 is closed due to the reason that described in the + /// COREWEBVIEW2_CLOSED_REASON enumeration. When this event is raised, the + /// webview2 moves to the Closed state, and cannot be used anymore. + HRESULT add_Closed( + [in] ICoreWebView2ClosedEventHandler* eventHandler, + [out] EventRegistrationToken* token); + + /// Remove an event handler previously added with `add_Closed`. + HRESULT remove_Closed( + [in] EventRegistrationToken token); + + /// `TRUE` if WebView2 has moved to the Closed state. Use `add_Closed` API + /// to get the specific closed reason. For more information see `add_Closed`. + [propget] HRESULT IsClosed([out, retval] BOOL* value); } + +/// The reason of webview2 closed. +[v1_enum] +typedef enum COREWEBVIEW2_CLOSED_REASON { + /// The CoreWebView2 has closed because its corresponding Profile has been or + /// marked as deleted. + COREWEBVIEW2_CLOSED_REASON_PROFILE_DELETED +} COREWEBVIEW2_CLOSED_REASON; + +/// Receives the webview2 `Closed` event. +[uuid(970BB7E0-A257-4A76-BE15-5BDEB00B5673), object, pointer_default(unique)] +interface ICoreWebView2ClosedEventHandler : IUnknown { + /// Called to provide the implementer with the event args for the + /// corresponding event. + HRESULT Invoke([in] ICoreWebView2_20* sender, + [in] ICoreWebView2ClosedEventArgs* args); +} + +/// This is the event args interface for webview2 `Closed` event handle. +[uuid(0e1730c1-03df-4ad2-b847-be4d63adf777), object, pointer_default(unique)] +interface ICoreWebView2ClosedEventArgs : IUnknown { + /// webview2 closed reason. + [propget] HRESULT Reason([out, retval] + COREWEBVIEW2_CLOSED_REASON* value); +} + ``` ## .NET and WinRT @@ -409,11 +509,31 @@ namespace Microsoft.Web.WebView2.Core CoreWebView2ControllerWindowReference ParentWindow, CoreWebView2ControllerOptions options); } - + + runtimeclass WebView2 + { + bool IsClosed { get; }; + } + runtimeclass CoreWebView2 { // ... CoreWebView2Profile Profile { get; }; + + [interface_name("Microsoft.Web.WebView2.Core.ICoreWebView2_9")] + { + event Windows.Foundation.TypedEventHandler Closed; + } + } + + enum CoreWebView2ClosedReason + { + ProfileDeleted, + }; + + runtimeclass CoreWebView2ClosedEventArgs + { + CoreWebView2ClosedReason Reason { get; }; } runtimeclass CoreWebView2Profile @@ -426,9 +546,9 @@ namespace Microsoft.Web.WebView2.Core CoreWebView2CookieManager CookieManager { get; }; - [interface_name("Microsoft.Web.WebView2.Core.ICoreWebView2Profile3")] + [interface_name("Microsoft.Web.WebView2.Core.ICoreWebView2Profile4")] { - // ICoreWebView2Profile3 members + // ICoreWebView2Profile4 members void Delete(); } }