Skip to content

Commit 2449abc

Browse files
authored
Move projects to use latest WebView2 SDK 1.0.902-prerelease (#92)
* Updates for Win32, WPF and WinForms sample apps from official/864m91 * Updates for Win32, WPF and WinForms sample apps for 1.0.901-prerelease * Move projects to use .NET Core 3.1 * Move projects to use WebView2 SDK 1.0.901-prerelease * Revert "Move projects to use .NET Core 3.1" This reverts commit ab3c273. * 901 -> 902
1 parent 5d64387 commit 2449abc

40 files changed

+1621
-521
lines changed

SampleApps/WebView2APISample/.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,5 +32,8 @@ packages/
3232
# Nuget.exe is downloaded by UseNuget.ps1
3333
nuget.exe
3434

35+
# Created by UseNuget.ps1
36+
NuGet.Config
37+
3538
# WIX log file
3639
UpgradeLog.htm
1.94 MB
Binary file not shown.

SampleApps/WebView2APISample/AppWindow.cpp

Lines changed: 133 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include <Shellapi.h>
1818
#include <ShlObj_core.h>
1919
#include <winrt/windows.system.h>
20+
2021
#include "App.h"
2122
#include "AppStartPage.h"
2223
#include "CheckFailure.h"
@@ -28,6 +29,7 @@
2829
#include "ScenarioAddHostObject.h"
2930
#include "ScenarioAuthentication.h"
3031
#include "ScenarioCookieManagement.h"
32+
#include "ScenarioClientCertificateRequested.h"
3133
#include "ScenarioCustomDownloadExperience.h"
3234
#include "ScenarioDOMContentLoaded.h"
3335
#include "ScenarioNavigateWithWebResourceRequest.h"
@@ -96,11 +98,11 @@ DWORD WINAPI DownloadAndInstallWV2RT(_In_ LPVOID lpParameter)
9698
// Creates a new window which is a copy of the entire app, but on the same thread.
9799
AppWindow::AppWindow(
98100
UINT creationModeId,
99-
std::wstring initialUri,
100-
std::wstring userDataFolderParam,
101+
std::wstring initialUri,
102+
std::wstring userDataFolderParam,
101103
bool isMainWindow,
102-
std::function<void()> webviewCreatedCallback,
103-
bool customWindowRect,
104+
std::function<void()> webviewCreatedCallback,
105+
bool customWindowRect,
104106
RECT windowRect,
105107
bool shouldHaveToolbar
106108
)
@@ -135,7 +137,7 @@ AppWindow::AppWindow(
135137
}
136138

137139
m_appBackgroundImageHandle = (HBITMAP)LoadImage(
138-
NULL, L"AppBackground.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
140+
g_hInstance, MAKEINTRESOURCE(IDI_WEBVIEW2_BACKGROUND), IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR);
139141
GetObject(m_appBackgroundImageHandle, sizeof(m_appBackgroundImage), &m_appBackgroundImage);
140142
m_memHdc = CreateCompatibleDC(GetDC(m_mainWindow));
141143
SelectObject(m_memHdc, m_appBackgroundImageHandle);
@@ -161,7 +163,7 @@ AppWindow::AppWindow(
161163
ShowWindow(m_mainWindow, g_nCmdShow);
162164
UpdateWindow(m_mainWindow);
163165

164-
// If no WebVieRuntime installed, create new thread to do install/download.
166+
// If no WebView2 Runtime installed, create new thread to do install/download.
165167
// Otherwise just initialize webview.
166168
wil::unique_cotaskmem_string version_info;
167169
HRESULT hr = GetAvailableCoreWebView2BrowserVersionString(nullptr, &version_info);
@@ -277,20 +279,13 @@ bool AppWindow::HandleWindowMessage(
277279
{
278280
PAINTSTRUCT ps;
279281
HDC hdc;
280-
RECT mainWindowBounds;
281-
RECT webViewBounds = {0};
282282
BeginPaint(hWnd, &ps);
283283

284284
hdc = GetDC(hWnd);
285-
GetClientRect(hWnd, &mainWindowBounds);
286-
287-
if (auto viewComponent = GetComponent<ViewComponent>())
288-
{
289-
webViewBounds = viewComponent->GetBounds();
290-
}
291285

292-
StretchBlt(hdc, webViewBounds.left, webViewBounds.top, webViewBounds.right, webViewBounds.bottom,
293-
m_memHdc, 0, 0, m_appBackgroundImage.bmWidth, m_appBackgroundImage.bmHeight, SRCCOPY);
286+
StretchBlt(hdc, m_appBackgroundImageRect.left, m_appBackgroundImageRect.top,
287+
m_appBackgroundImageRect.right, m_appBackgroundImageRect.bottom, m_memHdc,
288+
0, 0, m_appBackgroundImage.bmWidth, m_appBackgroundImage.bmHeight, SRCCOPY);
294289

295290
EndPaint(hWnd, &ps);
296291
return true;
@@ -466,6 +461,11 @@ bool AppWindow::ExecuteWebViewCommands(WPARAM wParam, LPARAM lParam)
466461
NewComponent<ScenarioCustomDownloadExperience>(this);
467462
return true;
468463
}
464+
case IDM_SCENARIO_USE_DEFERRED_CUSTOM_CLIENT_CERTIFICATE_DIALOG:
465+
{
466+
NewComponent<ScenarioClientCertificateRequested>(this);
467+
return true;
468+
}
469469
}
470470
return false;
471471
}
@@ -800,6 +800,12 @@ HRESULT AppWindow::OnCreateCoreWebView2ControllerCompleted(HRESULT result, ICore
800800
// browser might not have support for the latest version of the
801801
// ICoreWebView2_N interface.
802802
coreWebView2.query_to(&m_webView);
803+
// Save PID of the browser process serving last WebView created from our
804+
// CoreWebView2Environment. We know the controller was created with
805+
// S_OK, and it hasn't been closed (we haven't called Close and no
806+
// ProcessFailed event could have been raised yet) so the PID is
807+
// available.
808+
CHECK_FAILURE(m_webView->get_BrowserProcessId(&m_newestBrowserPid));
803809
// Create components. These will be deleted when the WebView is closed.
804810
NewComponent<FileComponent>(this);
805811
NewComponent<ProcessComponent>(this);
@@ -838,17 +844,10 @@ HRESULT AppWindow::OnCreateCoreWebView2ControllerCompleted(HRESULT result, ICore
838844
m_onWebViewFirstInitialized = nullptr;
839845
}
840846

841-
if (m_initialUri.empty())
842-
{
843-
// StartPage uses initialized values of the WebView and Environment
844-
// so we wait to call StartPage::GetUri until after the WebView is
845-
// created.
846-
m_initialUri = AppStartPage::GetUri(this);
847-
}
848-
849847
if (m_initialUri != L"none")
850848
{
851-
CHECK_FAILURE(m_webView->Navigate(m_initialUri.c_str()));
849+
std::wstring initialUri = m_initialUri.empty() ? AppStartPage::GetUri(this) : m_initialUri;
850+
CHECK_FAILURE(m_webView->Navigate(initialUri.c_str()));
852851
}
853852
}
854853
else
@@ -1090,49 +1089,134 @@ void AppWindow::ResizeEverything()
10901089
{
10911090
view->SetBounds(availableBounds);
10921091
}
1092+
m_appBackgroundImageRect = availableBounds;
10931093
}
10941094

10951095
//! [Close]
10961096
// Close the WebView and deinitialize related state. This doesn't close the app window.
10971097
void AppWindow::CloseWebView(bool cleanupUserDataFolder)
10981098
{
1099+
// 1. Delete components.
10991100
DeleteAllComponents();
1101+
1102+
// 2. If cleanup needed and BrowserProcessExited event interface available,
1103+
// register to cleanup upon browser exit.
1104+
wil::com_ptr<ICoreWebView2ExperimentalEnvironment4> experimentalEnvironment4;
1105+
if (m_webViewEnvironment)
1106+
{
1107+
experimentalEnvironment4 =
1108+
m_webViewEnvironment.try_query<ICoreWebView2ExperimentalEnvironment4>();
1109+
}
1110+
if (cleanupUserDataFolder && experimentalEnvironment4)
1111+
{
1112+
// Before closing the WebView, register a handler with code to run once the
1113+
// browser process and associated processes are terminated.
1114+
CHECK_FAILURE(experimentalEnvironment4->add_BrowserProcessExited(
1115+
Callback<ICoreWebView2ExperimentalBrowserProcessExitedEventHandler>(
1116+
[experimentalEnvironment4, this](
1117+
ICoreWebView2Environment* sender,
1118+
ICoreWebView2ExperimentalBrowserProcessExitedEventArgs* args) {
1119+
COREWEBVIEW2_BROWSER_PROCESS_EXIT_KIND kind;
1120+
UINT32 pid;
1121+
CHECK_FAILURE(args->get_BrowserProcessExitKind(&kind));
1122+
CHECK_FAILURE(args->get_BrowserProcessId(&pid));
1123+
1124+
// If a new WebView is created from this CoreWebView2Environment after
1125+
// the browser has exited but before our handler gets to run, a new
1126+
// browser process will be created and lock the user data folder
1127+
// again. Do not attempt to cleanup the user data folder in these
1128+
// cases. We check the PID of the exited browser process against the
1129+
// PID of the browser process to which our last CoreWebView2 attached.
1130+
if (pid == m_newestBrowserPid)
1131+
{
1132+
// Watch for graceful browser process exit. Let ProcessFailed event
1133+
// handler take care of failed browser process termination.
1134+
if (kind == COREWEBVIEW2_BROWSER_PROCESS_EXIT_KIND_NORMAL)
1135+
{
1136+
CHECK_FAILURE(experimentalEnvironment4->remove_BrowserProcessExited(
1137+
m_browserExitedEventToken));
1138+
// Release the environment only after the handler is invoked.
1139+
// Otherwise, there will be no environment to raise the event when
1140+
// the collection of WebView2 Runtime processes exit.
1141+
m_webViewEnvironment = nullptr;
1142+
CleanupUserDataFolder();
1143+
}
1144+
}
1145+
else
1146+
{
1147+
// The exiting process is not the last in use. Do not attempt cleanup
1148+
// as we might still have a webview open over the user data folder.
1149+
// Do not block from event handler.
1150+
RunAsync([this]() {
1151+
MessageBox(
1152+
m_mainWindow,
1153+
L"A new browser process prevented cleanup of the user data folder.",
1154+
L"Cleanup User Data Folder", MB_OK);
1155+
});
1156+
}
1157+
1158+
return S_OK;
1159+
})
1160+
.Get(),
1161+
&m_browserExitedEventToken));
1162+
}
1163+
1164+
// 3. Close the webview.
11001165
if (m_controller)
11011166
{
11021167
m_controller->Close();
11031168
m_controller = nullptr;
11041169
m_webView = nullptr;
11051170
m_webView3 = nullptr;
11061171
}
1107-
m_webViewEnvironment = nullptr;
1108-
if (cleanupUserDataFolder)
1109-
{
1110-
// For non-UWP apps, the default user data folder {Executable File Name}.WebView2
1111-
// is in the same directory next to the app executable. If end
1112-
// developers specify userDataFolder during WebView environment
1113-
// creation, they would need to pass in that explicit value here.
1114-
// For more information about userDataFolder:
1115-
// https://docs.microsoft.com/microsoft-edge/webview2/reference/win32/webview2-idl#createcorewebview2environmentwithoptions
1116-
WCHAR userDataFolder[MAX_PATH] = L"";
1117-
// Obtain the absolute path for relative paths that include "./" or "../"
1118-
_wfullpath(
1119-
userDataFolder, GetLocalPath(L".WebView2", true).c_str(), MAX_PATH);
1120-
std::wstring userDataFolderPath(userDataFolder);
1121-
1122-
std::wstring message = L"Are you sure you want to clean up the user data folder at\n";
1123-
message += userDataFolderPath;
1124-
message += L"\n?\nWarning: This action is not reversible.\n\n";
1125-
message += L"Click No if there are other open WebView instances.\n";
1126-
1127-
if (MessageBox(m_mainWindow, message.c_str(), L"Cleanup User Data Folder", MB_YESNO) ==
1128-
IDYES)
1172+
1173+
// 4. If BrowserProcessExited event interface is not available, release
1174+
// environment and proceed to cleanup immediately. If the interface is
1175+
// available, release environment only if not waiting for the event.
1176+
if (!experimentalEnvironment4)
1177+
{
1178+
m_webViewEnvironment = nullptr;
1179+
if (cleanupUserDataFolder)
11291180
{
1130-
CHECK_FAILURE(DeleteFileRecursive(userDataFolderPath));
1181+
CleanupUserDataFolder();
11311182
}
11321183
}
1184+
else if (!cleanupUserDataFolder)
1185+
{
1186+
// Release the environment object here only if no cleanup is needed.
1187+
// If cleanup is needed, the environment object release is deferred
1188+
// until the browser process exits, otherwise the handler for the
1189+
// BrowserProcessExited event will not be called.
1190+
m_webViewEnvironment = nullptr;
1191+
}
11331192
}
11341193
//! [Close]
11351194

1195+
void AppWindow::CleanupUserDataFolder()
1196+
{
1197+
// For non-UWP apps, the default user data folder {Executable File Name}.WebView2
1198+
// is in the same directory next to the app executable. If end
1199+
// developers specify userDataFolder during WebView environment
1200+
// creation, they would need to pass in that explicit value here.
1201+
// For more information about userDataFolder:
1202+
// https://docs.microsoft.com/microsoft-edge/webview2/reference/win32/webview2-idl#createcorewebview2environmentwithoptions
1203+
WCHAR userDataFolder[MAX_PATH] = L"";
1204+
// Obtain the absolute path for relative paths that include "./" or "../"
1205+
_wfullpath(userDataFolder, GetLocalPath(L".WebView2", true).c_str(), MAX_PATH);
1206+
std::wstring userDataFolderPath(userDataFolder);
1207+
1208+
std::wstring message = L"Are you sure you want to clean up the user data folder at\n";
1209+
message += userDataFolderPath;
1210+
message += L"\n?\nWarning: This action is not reversible.\n\n";
1211+
message += L"Click No if there are other open WebView instances.\n";
1212+
1213+
if (MessageBox(m_mainWindow, message.c_str(), L"Cleanup User Data Folder", MB_YESNO) ==
1214+
IDYES)
1215+
{
1216+
CHECK_FAILURE(DeleteFileRecursive(userDataFolderPath));
1217+
}
1218+
}
1219+
11361220
HRESULT AppWindow::DeleteFileRecursive(std::wstring path)
11371221
{
11381222
wil::com_ptr<IFileOperation> fileOperation;
@@ -1148,7 +1232,7 @@ HRESULT AppWindow::DeleteFileRecursive(std::wstring path)
11481232

11491233
// Add the operation
11501234
CHECK_FAILURE(fileOperation->DeleteItem(userDataFolder.get(), NULL));
1151-
CHECK_FAILURE(userDataFolder->Release());
1235+
userDataFolder.reset();
11521236

11531237
// Perform the operation to delete the directory
11541238
CHECK_FAILURE(fileOperation->PerformOperations());

SampleApps/WebView2APISample/AppWindow.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ class AppWindow
104104
void ReinitializeWebViewWithNewBrowser();
105105
void RestartApp();
106106
void CloseWebView(bool cleanupUserDataFolder = false);
107+
void CleanupUserDataFolder();
107108
void CloseAppWindow();
108109
void ChangeLanguage();
109110
void UpdateCreationModeMenu();
@@ -139,6 +140,9 @@ class AppWindow
139140
wil::com_ptr<ICoreWebView2> m_webView;
140141
wil::com_ptr<ICoreWebView2_3> m_webView3;
141142

143+
EventRegistrationToken m_browserExitedEventToken = {};
144+
UINT32 m_newestBrowserPid = 0;
145+
142146
// All components are deleted when the WebView is closed.
143147
std::vector<std::unique_ptr<ComponentBase>> m_components;
144148
std::unique_ptr<SettingsComponent> m_oldSettingsComponent;
@@ -170,6 +174,7 @@ class AppWindow
170174
HBITMAP m_appBackgroundImageHandle;
171175
BITMAP m_appBackgroundImage;
172176
HDC m_memHdc;
177+
RECT m_appBackgroundImageRect;
173178
};
174179

175180
template <class ComponentType, class... Args> void AppWindow::NewComponent(Args&&... args)

0 commit comments

Comments
 (0)