2020
2121#include " App.h"
2222#include " AppStartPage.h"
23+ #include " AudioComponent.h"
2324#include " CheckFailure.h"
2425#include " ControlComponent.h"
2526#include " DpiUtil.h"
3334#include " ScenarioCustomDownloadExperience.h"
3435#include " ScenarioDOMContentLoaded.h"
3536#include " ScenarioNavigateWithWebResourceRequest.h"
36- #include " ScenarioVirtualHostMappingForSW.h"
3737#include " ScenarioVirtualHostMappingForPopUpWindow.h"
38+ #include " ScenarioVirtualHostMappingForSW.h"
3839#include " ScenarioWebMessage.h"
3940#include " ScenarioWebViewEventMonitor.h"
4041#include " ScriptComponent.h"
4142#include " SettingsComponent.h"
4243#include " TextInputDialog.h"
4344#include " ViewComponent.h"
45+
4446using namespace Microsoft ::WRL;
4547static constexpr size_t s_maxLoadString = 100 ;
4648static constexpr UINT s_runAsyncWindowMessage = WM_APP;
@@ -96,9 +98,62 @@ DWORD WINAPI DownloadAndInstallWV2RT(_In_ LPVOID lpParameter)
9698 return returnCode;
9799}
98100
101+ static INT_PTR CALLBACK DlgProcStatic (HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
102+ {
103+ auto app = (AppWindow*)GetWindowLongPtr (hDlg, GWLP_USERDATA);
104+
105+ switch (message)
106+ {
107+ case WM_INITDIALOG:
108+ {
109+ app = (AppWindow*)lParam;
110+ SetWindowLongPtr (hDlg, GWLP_USERDATA, (LONG_PTR)app);
111+
112+ SetDlgItemText (hDlg, IDC_EDIT_PROFILE, app->GetWebViewOption ().profile .c_str ());
113+ CheckDlgButton (hDlg, IDC_CHECK_INPRIVATE, app->GetWebViewOption ().isInPrivate );
114+ return (INT_PTR)TRUE ;
115+ }
116+ case WM_COMMAND:
117+ {
118+ if (LOWORD (wParam) == IDOK)
119+ {
120+ int length = GetWindowTextLength (GetDlgItem (hDlg, IDC_EDIT_PROFILE));
121+ wchar_t text[MAX_PATH] = {};
122+ GetDlgItemText (hDlg, IDC_EDIT_PROFILE, text, length + 1 );
123+ bool inPrivate = IsDlgButtonChecked (hDlg, IDC_CHECK_INPRIVATE);
124+
125+ WebViewCreateOption opt (std::wstring (std::move (text)), inPrivate, WebViewCreateEntry::EVER_FROM_CREATE_WITH_OPTION_MENU);
126+
127+ // create app window
128+ new AppWindow (app->GetCreationModeId (), opt);
129+ }
130+
131+ if (LOWORD (wParam) == IDOK || LOWORD (wParam) == IDCANCEL)
132+ {
133+ EndDialog (hDlg, LOWORD (wParam));
134+ return (INT_PTR)TRUE ;
135+ }
136+ break ;
137+ }
138+ case WM_NCDESTROY:
139+ SetWindowLongPtr (hDlg, GWLP_USERDATA, NULL );
140+ return (INT_PTR)TRUE ;
141+ }
142+ return (INT_PTR)FALSE ;
143+ }
144+
145+ void WebViewCreateOption::PopupDialog (AppWindow* app)
146+ {
147+ DialogBoxParam (
148+ g_hInstance, MAKEINTRESOURCE (IDD_WEBVIEW2_OPTION), app->GetMainWindow (), DlgProcStatic,
149+ (LPARAM)app);
150+ }
151+
152+
99153// Creates a new window which is a copy of the entire app, but on the same thread.
100154AppWindow::AppWindow (
101155 UINT creationModeId,
156+ const WebViewCreateOption& opt,
102157 const std::wstring& initialUri,
103158 const std::wstring& userDataFolderParam,
104159 bool isMainWindow,
@@ -108,11 +163,13 @@ AppWindow::AppWindow(
108163 bool shouldHaveToolbar
109164 )
110165 : m_creationModeId(creationModeId),
166+ m_webviewOption(opt),
111167 m_initialUri(initialUri),
112168 m_onWebViewFirstInitialized(webviewCreatedCallback)
113169{
114170 // Initialize COM as STA.
115171 CHECK_FAILURE (OleInitialize (NULL ));
172+
116173 ++s_appInstances;
117174
118175 WCHAR szTitle[s_maxLoadString]; // The title bar text
@@ -580,7 +637,7 @@ bool AppWindow::ExecuteAppCommands(WPARAM wParam, LPARAM lParam)
580637 InitializeWebView ();
581638 return true ;
582639 case IDM_NEW_WINDOW:
583- new AppWindow (m_creationModeId);
640+ new AppWindow (m_creationModeId, GetWebViewOption () );
584641 return true ;
585642 case IDM_NEW_THREAD:
586643 CreateNewThread (this );
@@ -591,6 +648,9 @@ bool AppWindow::ExecuteAppCommands(WPARAM wParam, LPARAM lParam)
591648 case IDM_TOGGLE_AAD_SSO:
592649 ToggleAADSSO ();
593650 return true ;
651+ case IDM_CREATE_WITH_OPTION:
652+ m_webviewOption.PopupDialog (this );
653+ return true ;
594654 case IDM_TOGGLE_TOPMOST_WINDOW:
595655 {
596656 bool isCurrentlyTopMost = (GetWindowLong (m_mainWindow, GWL_EXSTYLE) & WS_EX_TOPMOST) != 0 ;
@@ -674,7 +734,7 @@ std::function<void()> AppWindow::GetAcceleratorKeyFunction(UINT key)
674734 switch (key)
675735 {
676736 case ' N' :
677- return [this ] { new AppWindow (m_creationModeId); };
737+ return [this ] { new AppWindow (m_creationModeId, GetWebViewOption () ); };
678738 case ' Q' :
679739 return [this ] { CloseAppWindow (); };
680740 case ' S' :
@@ -802,6 +862,11 @@ HRESULT AppWindow::OnCreateEnvironmentCompleted(
802862 CHECK_FAILURE (result);
803863 m_webViewEnvironment = environment;
804864
865+ if (m_webviewOption.entry == WebViewCreateEntry::EVER_FROM_CREATE_WITH_OPTION_MENU)
866+ {
867+ return CreateControllerWithOptions ();
868+ }
869+
805870 auto webViewEnvironment3 =
806871 m_webViewEnvironment.try_query <ICoreWebView2Environment3>();
807872#ifdef USE_WEBVIEW2_WIN10
@@ -836,6 +901,86 @@ HRESULT AppWindow::OnCreateEnvironmentCompleted(
836901}
837902// ! [CreateCoreWebView2Controller]
838903
904+ HRESULT AppWindow::CreateControllerWithOptions ()
905+ {
906+ auto webViewEnvironment8 =
907+ m_webViewEnvironment.try_query <ICoreWebView2ExperimentalEnvironment8>();
908+ if (!webViewEnvironment8)
909+ {
910+ FeatureNotAvailable ();
911+ return S_OK;
912+ }
913+
914+ Microsoft::WRL::ComPtr<ICoreWebView2ExperimentalControllerOptions> options;
915+ HRESULT hr = webViewEnvironment8->CreateCoreWebView2ControllerOptions (
916+ m_webviewOption.profile .c_str (), m_webviewOption.isInPrivate , options.GetAddressOf ());
917+ if (hr == E_INVALIDARG)
918+ {
919+ ShowFailure (hr, L" Unable to create WebView2 due to an invalid profile name." );
920+ CloseAppWindow ();
921+ return S_OK;
922+ }
923+ CHECK_FAILURE (hr);
924+
925+ #ifdef USE_WEBVIEW2_WIN10
926+ if (m_dcompDevice || m_wincompCompositor)
927+ #else
928+ if (m_dcompDevice)
929+ #endif
930+ {
931+ CHECK_FAILURE (webViewEnvironment8->CreateCoreWebView2CompositionControllerWithOptions (
932+ m_mainWindow, options.Get (),
933+ Callback<ICoreWebView2CreateCoreWebView2CompositionControllerCompletedHandler>(
934+ [this ](
935+ HRESULT result,
936+ ICoreWebView2CompositionController* compositionController) -> HRESULT {
937+ auto controller =
938+ wil::com_ptr<ICoreWebView2CompositionController>(compositionController)
939+ .query <ICoreWebView2Controller>();
940+ return OnCreateCoreWebView2ControllerCompleted (result, controller.get ());
941+ })
942+ .Get ()));
943+ }
944+ else
945+ {
946+ CHECK_FAILURE (webViewEnvironment8->CreateCoreWebView2ControllerWithOptions (
947+ m_mainWindow, options.Get (),
948+ Callback<ICoreWebView2CreateCoreWebView2ControllerCompletedHandler>(
949+ this , &AppWindow::OnCreateCoreWebView2ControllerCompleted)
950+ .Get ()));
951+ }
952+
953+ return S_OK;
954+ }
955+
956+ void AppWindow::SetAppIcon (bool inPrivate)
957+ {
958+ HICON newSmallIcon = nullptr ;
959+ HICON newBigIcon = nullptr ;
960+ if (inPrivate)
961+ {
962+ static HICON smallInPrivateIcon = reinterpret_cast <HICON>(LoadImage (
963+ g_hInstance, MAKEINTRESOURCEW (IDI_WEBVIEW2APISAMPLE_INPRIVATE), IMAGE_ICON, 16 , 16 ,
964+ LR_DEFAULTCOLOR));
965+ static HICON bigInPrivateIcon = reinterpret_cast <HICON>(LoadImage (
966+ g_hInstance, MAKEINTRESOURCEW (IDI_WEBVIEW2APISAMPLE_INPRIVATE), IMAGE_ICON, 32 , 32 ,
967+ LR_DEFAULTCOLOR));
968+ newSmallIcon = smallInPrivateIcon;
969+ newBigIcon = bigInPrivateIcon;
970+ }
971+ else
972+ {
973+ static HICON smallIcon = LoadIcon (g_hInstance, MAKEINTRESOURCE (IDI_WEBVIEW2APISAMPLE));
974+ static HICON bigIcon = LoadIcon (g_hInstance, MAKEINTRESOURCE (IDI_SMALL));
975+ newSmallIcon = smallIcon;
976+ newBigIcon = bigIcon;
977+ }
978+ reinterpret_cast <HICON>(SendMessage (
979+ m_mainWindow, WM_SETICON, ICON_SMALL, reinterpret_cast <LPARAM>(newSmallIcon)));
980+ reinterpret_cast <HICON>(
981+ SendMessage (m_mainWindow, WM_SETICON, ICON_BIG, reinterpret_cast <LPARAM>(newBigIcon)));
982+ }
983+
839984// This is the callback passed to CreateCoreWebView2Controller. Here we initialize all WebView-related
840985// state and register most of our event handlers with the WebView.
841986HRESULT AppWindow::OnCreateCoreWebView2ControllerCompleted (HRESULT result, ICoreWebView2Controller* controller)
@@ -856,6 +1001,23 @@ HRESULT AppWindow::OnCreateCoreWebView2ControllerCompleted(HRESULT result, ICore
8561001 // ProcessFailed event could have been raised yet) so the PID is
8571002 // available.
8581003 CHECK_FAILURE (m_webView->get_BrowserProcessId (&m_newestBrowserPid));
1004+ auto webview2Experimental8 = coreWebView2.try_query <ICoreWebView2Experimental8>();
1005+ if (webview2Experimental8)
1006+ {
1007+ wil::com_ptr<ICoreWebView2ExperimentalProfile> profile;
1008+ CHECK_FAILURE (webview2Experimental8->get_Profile (&profile));
1009+ wil::unique_cotaskmem_string profile_path;
1010+ CHECK_FAILURE (profile->get_ProfilePath (&profile_path));
1011+ std::wstring str (profile_path.get ());
1012+ m_profileDirName = str.substr (str.find_last_of (L' \\ ' ) + 1 );
1013+ BOOL inPrivate = FALSE ;
1014+ CHECK_FAILURE (profile->get_IsInPrivateModeEnabled (&inPrivate));
1015+ // update window title with m_profileDirName
1016+ UpdateAppTitle ();
1017+
1018+ // update window icon
1019+ SetAppIcon (inPrivate);
1020+ }
8591021 // Create components. These will be deleted when the WebView is closed.
8601022 NewComponent<FileComponent>(this );
8611023 NewComponent<ProcessComponent>(this );
@@ -1053,12 +1215,12 @@ void AppWindow::RegisterEventHandlers()
10531215 if (!useDefaultWindow)
10541216 {
10551217 newAppWindow = new AppWindow (
1056- m_creationModeId, L" none" , m_userDataFolder, false , nullptr , true ,
1057- windowRect, !!shouldHaveToolbar);
1218+ m_creationModeId, GetWebViewOption (), L" none" , m_userDataFolder, false ,
1219+ nullptr , true , windowRect, !!shouldHaveToolbar);
10581220 }
10591221 else
10601222 {
1061- newAppWindow = new AppWindow (m_creationModeId, L" none" );
1223+ newAppWindow = new AppWindow (m_creationModeId, GetWebViewOption (), L" none" );
10621224 }
10631225 newAppWindow->m_isPopupWindow = true ;
10641226 newAppWindow->m_onWebViewFirstInitialized = [args, deferral, newAppWindow]() {
@@ -1254,6 +1416,9 @@ bool AppWindow::CloseWebView(bool cleanupUserDataFolder)
12541416 // BrowserProcessExited event will not be called.
12551417 m_webViewEnvironment = nullptr ;
12561418 }
1419+
1420+ // reset profile name
1421+ m_profileDirName = L" " ;
12571422 m_documentTitle = L" " ;
12581423 return true ;
12591424}
@@ -1371,12 +1536,17 @@ std::wstring AppWindow::GetDocumentTitle()
13711536
13721537void AppWindow::UpdateAppTitle () {
13731538 std::wstring str (m_appTitle);
1539+ if (!m_profileDirName.empty ())
1540+ {
1541+ str += L" - " + m_profileDirName;
1542+ }
13741543 if (!m_documentTitle.empty ())
13751544 {
13761545 str += L" - " + m_documentTitle;
13771546 }
13781547 SetWindowText (m_mainWindow, str.c_str ());
13791548}
1549+
13801550RECT AppWindow::GetWindowBounds ()
13811551{
13821552 RECT hwndBounds = {0 };
0 commit comments