diff --git a/SampleApps/WebView2APISample/AppWindow.cpp b/SampleApps/WebView2APISample/AppWindow.cpp index dd9a1d83..de558ca0 100644 --- a/SampleApps/WebView2APISample/AppWindow.cpp +++ b/SampleApps/WebView2APISample/AppWindow.cpp @@ -35,6 +35,7 @@ #include "ScenarioCustomScheme.h" #include "ScenarioCustomSchemeNavigate.h" #include "ScenarioDOMContentLoaded.h" +#include "ScenarioExtensionsManagement.h" #include "ScenarioIFrameDevicePermission.h" #include "ScenarioNavigateWithWebResourceRequest.h" #include "ScenarioSharedWorkerWRR.h" @@ -46,7 +47,6 @@ #include "SettingsComponent.h" #include "TextInputDialog.h" #include "ViewComponent.h" - using namespace Microsoft::WRL; static constexpr size_t s_maxLoadString = 100; static constexpr UINT s_runAsyncWindowMessage = WM_APP; @@ -472,6 +472,18 @@ bool AppWindow::ExecuteWebViewCommands(WPARAM wParam, LPARAM lParam) //! [GetUserDataFolder] return true; } + case IDM_GET_FAILURE_REPORT_FOLDER: + { + //! [GetFailureReportFolder] + auto experimental_environment = + m_webViewEnvironment.try_query(); + CHECK_FEATURE_RETURN(experimental_environment); + wil::unique_cotaskmem_string failureReportFolder; + experimental_environment->get_FailureReportFolderPath(&failureReportFolder); + MessageBox(m_mainWindow, failureReportFolder.get(), L"Failure Report Folder", MB_OK); + //! [GetFailureReportFolder] + return true; + } case IDM_CLOSE_WEBVIEW: { CloseWebView(); @@ -592,6 +604,26 @@ bool AppWindow::ExecuteWebViewCommands(WPARAM wParam, LPARAM lParam) NewComponent(this); return true; } + case IDM_SCENARIO_BROWSER_PRINT_PREVIEW: + { + return ShowPrintUI(COREWEBVIEW2_PRINT_DIALOG_KIND_BROWSER); + } + case IDM_SCENARIO_SYSTEM_PRINT: + { + return ShowPrintUI(COREWEBVIEW2_PRINT_DIALOG_KIND_SYSTEM); + } + case IDM_SCENARIO_PRINT_TO_DEFAULT_PRINTER: + { + return PrintToDefaultPrinter(); + } + case IDM_SCENARIO_PRINT_TO_PRINTER: + { + return PrintToPrinter(); + } + case IDM_SCENARIO_PRINT_TO_PDF_STREAM: + { + return PrintToPdfStream(); + } } return false; } @@ -693,6 +725,9 @@ bool AppWindow::ExecuteAppCommands(WPARAM wParam, LPARAM lParam) case IDM_TOGGLE_EXCLUSIVE_USER_DATA_FOLDER_ACCESS: ToggleExclusiveUserDataFolderAccess(); return true; + case IDM_TOGGLE_CUSTOM_CRASH_REPORTING: + ToggleCustomCrashReporting(); + return true; case IDM_SCENARIO_CLEAR_BROWSING_DATA_COOKIES: { return ClearBrowsingData(COREWEBVIEW2_BROWSING_DATA_KINDS_COOKIES); @@ -795,6 +830,249 @@ void AppWindow::ToggleExclusiveUserDataFolderAccess() L"Exclusive User Data Folder Access change", MB_OK); } +void AppWindow::ToggleCustomCrashReporting() +{ + m_CustomCrashReportingEnabled = !m_CustomCrashReportingEnabled; + MessageBox( + nullptr, + m_CustomCrashReportingEnabled ? L"Crash reporting will be disabled for new WebView " + L"created after all webviews are closed." + : L"Crash reporting will be enabled for new WebView " + L"created after all webviews are closed.", + L"Custom Crash Reporting", MB_OK); +} + +//! [ShowPrintUI] +// Shows the user a print dialog. If `printDialogKind` is +// COREWEBVIEW2_PRINT_DIALOG_KIND_BROWSER, opens a browser print preview dialog, +// COREWEBVIEW2_PRINT_DIALOG_KIND_SYSTEM opens a system print dialog. +bool AppWindow::ShowPrintUI(COREWEBVIEW2_PRINT_DIALOG_KIND printDialogKind) +{ + auto webView2Experimental17 = m_webView.try_query(); + CHECK_FEATURE_RETURN(webView2Experimental17); + CHECK_FAILURE(webView2Experimental17->ShowPrintUI(printDialogKind)); + return true; +} +//! [ShowPrintUI] + +// This example prints the current web page without a print dialog to default printer +// with the default print settings. +bool AppWindow::PrintToDefaultPrinter() +{ + wil::com_ptr webView2Experimental17; + CHECK_FAILURE(m_webView->QueryInterface(IID_PPV_ARGS(&webView2Experimental17))); + + wil::unique_cotaskmem_string title; + CHECK_FAILURE(m_webView->get_DocumentTitle(&title)); + + // Passing nullptr for `ICoreWebView2PrintSettings` results in default print settings used. + // Prints current web page with the default page and printer settings. + CHECK_FAILURE(webView2Experimental17->Print( + nullptr, Callback( + [title = std::move(title), + this](HRESULT errorCode, COREWEBVIEW2_PRINT_STATUS printStatus) -> HRESULT + { + std::wstring message = L""; + if (errorCode == S_OK && + printStatus == COREWEBVIEW2_PRINT_STATUS_SUCCEEDED) + { + message = L"Printing " + std::wstring(title.get()) + + L" document to printer is succedded"; + } + else if ( + errorCode == S_OK && + printStatus == COREWEBVIEW2_PRINT_STATUS_PRINTER_UNAVAILABLE) + { + message = L"Printer is not available, offline or error state"; + } + else if (errorCode == E_ABORT) + { + message = L"Printing " + std::wstring(title.get()) + + L" document is in progress"; + } + else + { + message = L"Printing " + std::wstring(title.get()) + + L" document to printer is failed"; + } + + AsyncMessageBox(message, L"Print to default printer"); + + return S_OK; + }) + .Get())); + return true; +} + +// Function to get printer name by displaying printer text input dialog to the user. +// User has to specify the desired printer name by querying the installed printers list on the +// OS to print the web page. You may also choose to display printers list to the user and return +// user selected printer. +std::wstring AppWindow::GetPrinterName() +{ + std::wstring printerName; + + TextInputDialog dialog( + GetMainWindow(), L"Printer Name", L"Printer Name:", + L"Specify a printer name from the installed printers list on the OS.", L""); + + if (dialog.confirmed) + { + printerName = (dialog.input).c_str(); + } + return printerName; + + // or + // + // Use win32 EnumPrinters function to get locally installed printers. + // Display the printer list to the user and get the user desired printer to print. + // Return the user selected printer name. +} + +// Function to get print settings for the selected printer. +// You may also choose get the capabilties from the native printer API, display to the user to +// get the print settings for the current web page and for the selected printer. +SamplePrintSettings AppWindow::GetSelectedPrinterPrintSettings(std::wstring printerName) +{ + SamplePrintSettings samplePrintSettings; + samplePrintSettings.PrintBackgrounds = true; + samplePrintSettings.HeaderAndFooter = true; + + return samplePrintSettings; + + // or + // + // Use win32 DeviceCapabilitiesA function to get the capabilities of the selected printer. + // Display the printer capabilities to the user along with the page settings. + // Return the user selected settings. +} + +//! [PrintToPrinter] +// This example prints the current web page to a specified printer with the settings. +bool AppWindow::PrintToPrinter() +{ + std::wstring printerName = GetPrinterName(); + // Host apps custom print settings based on the user selection. + SamplePrintSettings samplePrintSettings = GetSelectedPrinterPrintSettings(printerName); + + wil::com_ptr webView2Experimental17; + CHECK_FAILURE(m_webView->QueryInterface(IID_PPV_ARGS(&webView2Experimental17))); + + wil::com_ptr webviewEnvironment6; + CHECK_FAILURE(m_webViewEnvironment->QueryInterface(IID_PPV_ARGS(&webviewEnvironment6))); + + wil::com_ptr printSettings; + CHECK_FAILURE(webviewEnvironment6->CreatePrintSettings(&printSettings)); + + wil::com_ptr printSettings2; + CHECK_FAILURE(printSettings->QueryInterface(IID_PPV_ARGS(&printSettings2))); + + CHECK_FAILURE(printSettings->put_Orientation(samplePrintSettings.Orientation)); + CHECK_FAILURE(printSettings2->put_Copies(samplePrintSettings.Copies)); + CHECK_FAILURE(printSettings2->put_PagesPerSide(samplePrintSettings.PagesPerSide)); + CHECK_FAILURE(printSettings2->put_PageRanges(samplePrintSettings.Pages.c_str())); + if (samplePrintSettings.Media == COREWEBVIEW2_PRINT_MEDIA_SIZE_CUSTOM) + { + CHECK_FAILURE(printSettings->put_PageWidth(samplePrintSettings.PaperWidth)); + CHECK_FAILURE(printSettings->put_PageHeight(samplePrintSettings.PaperHeight)); + } + CHECK_FAILURE(printSettings2->put_ColorMode(samplePrintSettings.ColorMode)); + CHECK_FAILURE(printSettings2->put_Collation(samplePrintSettings.Collation)); + CHECK_FAILURE(printSettings2->put_Duplex(samplePrintSettings.Duplex)); + CHECK_FAILURE(printSettings->put_ScaleFactor(samplePrintSettings.ScaleFactor)); + CHECK_FAILURE( + printSettings->put_ShouldPrintBackgrounds(samplePrintSettings.PrintBackgrounds)); + CHECK_FAILURE( + printSettings->put_ShouldPrintBackgrounds(samplePrintSettings.PrintBackgrounds)); + CHECK_FAILURE( + printSettings->put_ShouldPrintHeaderAndFooter(samplePrintSettings.HeaderAndFooter)); + CHECK_FAILURE(printSettings->put_HeaderTitle(samplePrintSettings.HeaderTitle.c_str())); + CHECK_FAILURE(printSettings->put_FooterUri(samplePrintSettings.FooterUri.c_str())); + CHECK_FAILURE(printSettings2->put_PrinterName(printerName.c_str())); + + wil::unique_cotaskmem_string title; + CHECK_FAILURE(m_webView->get_DocumentTitle(&title)); + + CHECK_FAILURE(webView2Experimental17->Print( + printSettings.get(), + Callback( + [title = std::move(title), + this](HRESULT errorCode, COREWEBVIEW2_PRINT_STATUS printStatus) -> HRESULT + { + std::wstring message = L""; + if (errorCode == S_OK && printStatus == COREWEBVIEW2_PRINT_STATUS_SUCCEEDED) + { + message = L"Printing " + std::wstring(title.get()) + + L" document to printer is succedded"; + } + else if ( + errorCode == S_OK && + printStatus == COREWEBVIEW2_PRINT_STATUS_PRINTER_UNAVAILABLE) + { + message = L"Selected printer is not found, not available, offline or " + L"error state."; + } + else if (errorCode == E_INVALIDARG) + { + message = L"Invalid settings provided for the specified printer"; + } + else if (errorCode == E_ABORT) + { + message = L"Printing " + std::wstring(title.get()) + + L" document already in progress"; + } + else + { + message = L"Printing " + std::wstring(title.get()) + + L" document to printer is failed"; + } + + AsyncMessageBox(message, L"Print to printer"); + + return S_OK; + }) + .Get())); + return true; +} +//! [PrintToPrinter] + +// Function to display current web page pdf data in a custom print preview dialog. +static void DisplayPdfDataInPrintDialog(IStream* pdfData) +{ + // You can display the printable pdf data in a custom print preview dialog to the end user. +} + +//! [PrintToPdfStream] +// This example prints the Pdf data of the current page to a stream. +bool AppWindow::PrintToPdfStream() +{ + wil::com_ptr webView2Experimental17; + CHECK_FAILURE(m_webView->QueryInterface(IID_PPV_ARGS(&webView2Experimental17))); + + wil::unique_cotaskmem_string title; + CHECK_FAILURE(m_webView->get_DocumentTitle(&title)); + + // Passing nullptr for `ICoreWebView2PrintSettings` results in default print settings used. + CHECK_FAILURE(webView2Experimental17->PrintToPdfStream( + nullptr, + Callback( + [title = std::move(title), this](HRESULT errorCode, IStream* pdfData) -> HRESULT + { + DisplayPdfDataInPrintDialog(pdfData); + + std::wstring message = + L"Printing " + std::wstring(title.get()) + L" document to PDF Stream " + + ((errorCode == S_OK && pdfData != nullptr) ? L"succedded" : L"failed"); + + AsyncMessageBox(message, L"Print to PDF Stream"); + + return S_OK; + }) + .Get())); + return true; +} +//! [PrintToPdfStream] + // Message handler for about dialog. INT_PTR CALLBACK AppWindow::About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { @@ -924,6 +1202,13 @@ void AppWindow::InitializeWebView() } //! [CoreWebView2CustomSchemeRegistration] + Microsoft::WRL::ComPtr optionsExperimental2; + if (options.As(&optionsExperimental2) == S_OK) + { + CHECK_FAILURE(optionsExperimental2->put_IsCustomCrashReportingEnabled( + m_CustomCrashReportingEnabled ? TRUE : FALSE)); + } + HRESULT hr = CreateCoreWebView2EnvironmentWithOptions( subFolder, m_userDataFolder.c_str(), options.Get(), Callback( diff --git a/SampleApps/WebView2APISample/AppWindow.h b/SampleApps/WebView2APISample/AppWindow.h index f97c314e..d3aa40b4 100644 --- a/SampleApps/WebView2APISample/AppWindow.h +++ b/SampleApps/WebView2APISample/AppWindow.h @@ -61,6 +61,28 @@ struct WebViewCreateOption void PopupDialog(AppWindow* app); }; +// SamplePrintSettings also defaults to the defaults of the ICoreWebView2PrintSettings +// defaults. +struct SamplePrintSettings +{ + COREWEBVIEW2_PRINT_ORIENTATION Orientation = COREWEBVIEW2_PRINT_ORIENTATION_PORTRAIT; + int Copies = 1; + int PagesPerSide = 1; + std::wstring Pages = L""; + COREWEBVIEW2_PRINT_COLLATION Collation = COREWEBVIEW2_PRINT_COLLATION_DEFAULT; + COREWEBVIEW2_PRINT_COLOR_MODE ColorMode = COREWEBVIEW2_PRINT_COLOR_MODE_DEFAULT; + COREWEBVIEW2_PRINT_DUPLEX Duplex = COREWEBVIEW2_PRINT_DUPLEX_DEFAULT; + COREWEBVIEW2_PRINT_MEDIA_SIZE Media = COREWEBVIEW2_PRINT_MEDIA_SIZE_DEFAULT; + double PaperWidth = 8.5; + double PaperHeight = 11; + double ScaleFactor = 1.0; + bool PrintBackgrounds = false; + bool HeaderAndFooter = false; + bool ShouldPrintSelectionOnly = false; + std::wstring HeaderTitle = L""; + std::wstring FooterUri = L""; +}; + class AppWindow { public: @@ -180,11 +202,18 @@ class AppWindow bool ClearBrowsingData(COREWEBVIEW2_BROWSING_DATA_KINDS dataKinds); void UpdateAppTitle(); void ToggleExclusiveUserDataFolderAccess(); + void ToggleCustomCrashReporting(); #ifdef USE_WEBVIEW2_WIN10 void OnTextScaleChanged( winrt::Windows::UI::ViewManagement::UISettings const& uiSettings, winrt::Windows::Foundation::IInspectable const& args); #endif + bool ShowPrintUI(COREWEBVIEW2_PRINT_DIALOG_KIND printDialogKind); + bool PrintToDefaultPrinter(); + bool PrintToPrinter(); + std::wstring GetPrinterName(); + SamplePrintSettings GetSelectedPrinterPrintSettings(std::wstring printerName); + bool PrintToPdfStream(); std::wstring GetLocalPath(std::wstring path, bool keep_exe_path); void DeleteAllComponents(); @@ -237,6 +266,8 @@ class AppWindow bool m_AADSSOEnabled = false; bool m_ExclusiveUserDataFolderAccess = false; + bool m_CustomCrashReportingEnabled = false; + // Fullscreen related code RECT m_previousWindowRect; HMENU m_hMenu; diff --git a/SampleApps/WebView2APISample/ProcessComponent.cpp b/SampleApps/WebView2APISample/ProcessComponent.cpp index d8421aa9..851e20c7 100644 --- a/SampleApps/WebView2APISample/ProcessComponent.cpp +++ b/SampleApps/WebView2APISample/ProcessComponent.cpp @@ -234,6 +234,7 @@ std::wstring ProcessComponent::ProcessFailedReasonToString( REASON_ENTRY(COREWEBVIEW2_PROCESS_FAILED_REASON_CRASHED); REASON_ENTRY(COREWEBVIEW2_PROCESS_FAILED_REASON_LAUNCH_FAILED); REASON_ENTRY(COREWEBVIEW2_PROCESS_FAILED_REASON_OUT_OF_MEMORY); + REASON_ENTRY(COREWEBVIEW2_PROCESS_FAILED_REASON_PROFILE_DELETED); #undef REASON_ENTRY } diff --git a/SampleApps/WebView2APISample/README.md b/SampleApps/WebView2APISample/README.md index ed8724be..c7ebf4d8 100644 --- a/SampleApps/WebView2APISample/README.md +++ b/SampleApps/WebView2APISample/README.md @@ -1,5 +1,5 @@ --- -description: "Demonstrates the features and usage patterns of WebView2 in a Win32 app." +description: "Demonstrate the features and usage patterns of WebView2 in Win32." extendedZipContent: - path: SharedContent @@ -14,23 +14,346 @@ products: - microsoft-edge urlFragment: WebView2APISample --- -# Win32 sample app +# WebView2 API Sample - +This is a hybrid application built with the [Microsoft Edge WebView2](https://aka.ms/webview2) control. - -This sample, **WebView2APISample**, embeds a WebView2 control within a Win32 application. +![Sample App Snapshot](https://raw.githubusercontent.com/MicrosoftEdge/WebView2Samples/master/SampleApps/WebView2APISample/documentation/screenshots/sample-app-screenshot.png) - -This sample is built as a Win32 Visual Studio 2019 project. It uses C++ and HTML/CSS/JavaScript in the WebView2 environment. +The WebView2APISample is an example of an application that embeds a WebView within a Win32 native application. It is built as a Win32 [Visual Studio 2019](https://visualstudio.microsoft.com/vs/) project and makes use of both C++ and HTML/CSS/JavaScript in the WebView2 environment. - -To use this sample, see [Win32 sample app](https://docs.microsoft.com/microsoft-edge/webview2/samples/webview2apissample). +The API Sample showcases a selection of WebView2's event handlers and API methods that allow a native Win32 application to directly interact with a WebView and vice versa. - -The solution file for this sample is in the parent directory: `SampleApps/WebView2Samples.sln`. The solution file includes a copy of some of the other, sibling samples for other frameworks or platforms. +If this is your first time using WebView, we recommend first following the [Getting Started](https://docs.microsoft.com/microsoft-edge/webview2/gettingstarted/win32) guide, which goes over how to create a WebView2 and walks through some basic WebView2 functionality. - -This is the main WebView2 sample. The running **WebView2APISample** app window shows the WebView2 SDK version and also the WebView2 Runtime version and path. The **WebView2APISample** app has several menus containing many menuitems that demonstrate a broad range of WebView2 APIs: +To learn more specifics about events and API Handlers in WebView2, you can refer to the [WebView2 Reference Documentation](https://docs.microsoft.com/microsoft-edge/webview2/webview2-api-reference). -![Screenshot of WebView2APISample app, with many menus](documentation/screenshots/sample-app-screenshot.png) +## Prerequisites + +- [Microsoft Edge (Chromium)](https://www.microsoftedgeinsider.com/download/) installed on a supported OS. Currently we recommend the latest version of the Edge Canary channel. +- [Visual Studio](https://visualstudio.microsoft.com/vs/) with C++ support installed. +- Latest pre-release version of our [WebView2 SDK](https://aka.ms/webviewnuget), which is included in this project. + +## Build the WebView2 API Sample + +Clone the repository and open the solution in Visual Studio. WebView2 is already included as a NuGet package* in this project. + +- Clone this repository +- Open the solution in Visual Studio 2019** +- Set the target you want to build (Debug/Release, x86/x64/ARM64) +- Build the project file: _WebView2APISample.vcxproj_ + +That's it! Everything should be ready to just launch the app. + +*You can get the WebView2 NugetPackage through the Visual Studio NuGet Package Manager. + +**You can also use Visual Studio 2017 by changing the project's Platform Toolset in Project Properties/Configuration properties/General/Platform Toolset. You might also need to change the Windows SDK to the latest version available to you. + +## Application architecture + +The API Sample App is an example of a hybrid application. It has two parts: a Win32 native part and a WebView part. The Win32 part can access native Windows APIs, while the WebView container can utilize standard web technologies (HTML, CSS, JavaScript). + +This hybrid approach allows you to create and iterate faster using web technologies, while still being able to take advantage of native functionalities. The Sample App specifically demonstrates how both components can interact with each other. + +Both of these parts of the Sample App are displayed in the image below: + +![alt text](https://raw.githubusercontent.com/MicrosoftEdge/WebView2Samples/master/SampleApps/WebView2APISample/documentation/screenshots/sample-app-layout-diagram.png) + +1. Section One: The top part of the Sample App is a Win32 component written in C++. This part of the application takes in UI inputs from the user and uses them to control the WebView. + +2. Section Two: The main part of the Sample App is a WebView that can be repurposed using standard web technologies (HTML/CSS/JavaScript). It can be navigated to websites or local content. + +## Project Files + +This section briefly explains some key files within the repository. The WebView2APISample is divided vertically into components, instead of horizontally into layers. Each component implements the whole workflow of a category of example features, from listening for menu commands, to calling WebView API methods to implement them. + +#### 1. App.cpp + +This is the top-level file that runs the Sample App. It reads command line options, sets up the process environment, and handles the app's threading model. + +#### 2. AppWindow.cpp + +This file implements the application window. In this file, we first set up all the Win32 controls. Second, we initialize the WebView Environment and the WebView. Third, we add some event handlers to the WebView and create all the components that handle various features of the application. The `AppWindow` class itself handles commands from the application's Window menu. + +#### 3. FileComponent.cpp + +This component handles commands from the File menu (except for Exit), as well as the `DocumentTitleChanged` event. + +#### 4. ScriptComponent.cpp + +This component handles commands from the Script menu, which involve interacting with the WebView by injecting JavaScript, posting WebMessages, adding native objects to the webpage, or using the DevTools protocol to communicate with the webpage. + +#### 5. ProcessComponent.cpp + +This component handles commands from the Process menu, which involve interaction with the browser's process. It also handles the ProcessFailed event, in case the browser process or one of its render process crashes or is unresponsive. + +#### 6. SettingsComponent.cpp + +This component handles commands from the Settings menu, and is also in charge of copying settings from an old WebView when a new one is created. Most code that interacts with the `ICoreWebView2Settings` interface can be found here. + +#### 7. ViewComponent.cpp + +This component handles commands from the View menu, and any functionality related to sizing and visibility of the WebView. When the app window is resized, minimized, or restored, `ViewComponent` will resize, hide, or show the WebView in response. It also responds to the `ZoomFactorChanged` event. + +#### 8. ScenarioWebMessage.cpp and ScenarioWebMessage.html + +This component is created when you select the Scenario/Web Messaging menu item. It implements an example application with a C++ part and an HTML+JavaScript part, which communicate with each other by asynchronously posting and receiving messages. + +![alt text](https://raw.githubusercontent.com/MicrosoftEdge/WebView2Samples/master/SampleApps/WebView2APISample/documentation/screenshots/sample-app-webmessaging-screenshot.png) + +#### 9. ScenarioAddHostObject.cpp and ScenarioAddHostObject.html + +This component is created when you select the Scenario/Host Objects menu item. It demonstrates communication between the native app and the HTML webpage by means of host object injection. The interface of the host object is declared in `HostObjectSample.idl`, and the object itself is implemented in `HostObjectSampleImpl.cpp`. + +## Key Functions + +The section below briefly explains some of the key functions in the Sample App. + +### AppWindow.cpp + +#### InitializeWebView() + +In the AppWindow file, we use the InitializeWebView() function to create the WebView2 environment by using [CreateCoreWebView2EnvironmentWithOptions](https://docs.microsoft.com/microsoft-edge/webview2/reference/win32/webview2-idl#createcorewebview2environmentwithoptions). + +Once we've created the environment, we create the WebView by using `CreateCoreWebView2Controller`. + +To see these API calls in action, refer to the following code snippet from `InitializeWebView()`. + +```cpp +HRESULT hr = CreateCoreWebView2EnvironmentWithOptions( + subFolder, nullptr, options.Get(), + Callback( + this, &AppWindow::OnCreateEnvironmentCompleted) + .Get()); +if (!SUCCEEDED(hr)) +{ + if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) + { + MessageBox( + m_mainWindow, + L"Couldn't find Edge installation. " + "Do you have a version installed that's compatible with this " + "WebView2 SDK version?", + nullptr, MB_OK); + } + else + { + ShowFailure(hr, L"Failed to create webview environment"); + } +} +``` + +#### OnCreateEnvironmentCompleted() + +This callback function is passed to `CreateCoreWebView2EnvironmentWithOptions` in `InitializeWebView()`. It stored the environment pointer and then uses it to create a new WebView. + +```cpp +HRESULT AppWindow::OnCreateEnvironmentCompleted( + HRESULT result, ICoreWebView2Environment* environment) +{ + CHECK_FAILURE(result); + + m_webViewEnvironment = environment; + + CHECK_FAILURE(m_webViewEnvironment->CreateCoreWebView2Controller( + m_mainWindow, Callback( + this, &AppWindow::OnCreateCoreWebView2ControllerCompleted) + .Get())); + return S_OK; +} +``` + +#### OnCreateCoreWebView2ControllerCompleted() + +This callback function is passed to `CreateCoreWebView2Controller` in `InitializeWebView()`. Here, we initialize the WebView-related state, register some event handlers, and create the app components. + +#### RegisterEventHandlers() + +This function is called within `CreateCoreWebView2Controller`. It sets up some of the event handlers used by the application, and adds them to the WebView. + +To read more about event handlers in WebView2, you can refer to this [documentation](https://docs.microsoft.com/microsoft-edge/webview2/reference/win32/icorewebview2). + +Below is a code snippet from `RegisterEventHandlers()`, where we set up an event handler for the `NewWindowRequested` event. This event is fired when JavaScript in the webpage calls `window.open()`, and our handler makes a new `AppWindow` and passes the new window's WebView back to the browser so it can return it from the `window.open()` call. Unlike our calls to `CreateCoreWebView2EnvironmentWithOptions` and `CreateCoreWebView2Controller`, instead of providing a method for the callback, we just provide a C++ lambda right then and there. + +```cpp +CHECK_FAILURE(m_webView->add_NewWindowRequested( + Callback( + [this]( + ICoreWebView2* sender, + ICoreWebView2NewWindowRequestedEventArgs* args) { + wil::com_ptr deferral; + CHECK_FAILURE(args->GetDeferral(&deferral)); + + auto newAppWindow = new AppWindow(L""); + newAppWindow->m_isPopupWindow = true; + newAppWindow->m_onWebViewFirstInitialized = [args, deferral, newAppWindow]() { + CHECK_FAILURE(args->put_NewWindow(newAppWindow->m_webView.get())); + CHECK_FAILURE(args->put_Handled(TRUE)); + CHECK_FAILURE(deferral->Complete()); + }; + + return S_OK; + }) + .Get(), + nullptr)); +``` + +### ScenarioWebMessage + +The `ScenarioWebMessage` files show how the Win32 Host can modify the WebView, how the WebView can modify the Win32Host, and how the WebView can modify itself by accessing information from the Win32 Host. This is done asynchronously. + +The following sections demonstrate how each discrete function works using the Sample App and then explains how to implement this functionality. + +First, navigate to the ScenarioWebMessage application within the Sample App, using the following steps: + +1. Open the Sample App +2. Click on Scenario +3. Click on Web Messaging + +The WebView should display a simple webpage titled: "WebMessage sample page". The code for this page can be found in the `ScenarioWebMessage.html` file. + +![alt text](https://raw.githubusercontent.com/MicrosoftEdge/WebView2Samples/master/SampleApps/WebView2APISample/documentation/screenshots/sample-app-webmessaging-screenshot.png) + +To better understand ScenarioWebMessage functionality, you can either follow the instructions on the page or the steps detailed below. + +#### 1. Posting Messages (Win32 Host to WebView) + +The following steps show how the Win32 Host can modify a WebView. In this example, you will turn the text blue: + +1. Click on Script in the Toolbar +2. Click on Post Web Message JSON + +A dialog box with the pre-written code `{"SetColor":"blue"}` should appear. + +3. Click OK + +The text under Posting Messages should now be blue. + +Here's how it works: + +1. In `ScriptComponent.cpp`, we use [PostWebMessageAsJson](https://docs.microsoft.com/microsoft-edge/webview2/reference/win32/icorewebview2#postwebmessageasjson) to post user input to the `ScenarioMessage.html` web application. + +```cpp +// Prompt the user for some JSON and then post it as a web message. +void ScriptComponent::SendJsonWebMessage() +{ + TextInputDialog dialog( + m_appWindow->GetMainWindow(), + L"Post Web Message JSON", + L"Web message JSON:", + L"Enter the web message as JSON.", + L"{\"SetColor\":\"blue\"}"); + if (dialog.confirmed) + { + m_webView->PostWebMessageAsJson(dialog.input.c_str()); + } +} +``` + +2. Within the web application, event listeners are used to receive and respond to the web message. The code snippet below is from `ScenarioWebMessage.html`. The event listener changes the color of the text if it reads "SetColor". + +```js +window.chrome.webview.addEventListener('message', arg => { + if ("SetColor" in arg.data) { + document.getElementById("colorable").style.color = arg.data.SetColor; + } +}); +``` + +#### 2. Receiving Messages (WebView to Win32 Host) + +The following steps show how the WebView can modify the Win32 Host App by changing the title of the Win32 App: + +1. Locate the Title of the Sample App - the top left of the window next to the icon. +2. Under the Receiving Message section, fill out the form with the new title of your choice. +3. Click Send + +Locate the Title of the Sample App, it should have changed to the title you have just inputted. + +Here's how it works: + +1. Within `ScenarioWebMessage.html`, we call [window.chrome.webview.postMessage()](https://developer.mozilla.org/docs/Web/API/Window/postMessage) to send the user input to the host application. Refer to code snippet below: + +```js +function SetTitleText() { + let titleText = document.getElementById("title-text"); + window.chrome.webview.postMessage(`SetTitleText ${titleText.value}`); +} +``` + +2. Within `ScenarioWebMessage.cpp`, we use [add_WebMessageReceived](https://docs.microsoft.com/microsoft-edge/webview2/reference/win32/icorewebview2#add_webmessagereceived) to register the event handler. When we receive the event, after validating the input, we change the title of the App Window. + +```cpp +// Setup the web message received event handler before navigating to +// ensure we don't miss any messages. +CHECK_FAILURE(m_webview->add_WebMessageReceived( + Microsoft::WRL::Callback( + [this](ICoreWebView2* sender, ICoreWebView2WebMessageReceivedEventArgs* args) +{ + wil::unique_cotaskmem_string uri; + CHECK_FAILURE(args->get_Source(&uri)); + + // Always validate that the origin of the message is what you expect. + if (uri.get() != m_sampleUri) + { + return S_OK; + } + wil::unique_cotaskmem_string messageRaw; + CHECK_FAILURE(args->TryGetWebMessageAsString(&messageRaw)); + std::wstring message = messageRaw.get(); + + if (message.compare(0, 13, L"SetTitleText ") == 0) + { + m_appWindow->SetTitleText(message.substr(13).c_str()); + } + return S_OK; +}).Get(), &m_webMessageReceivedToken)); +``` + +#### 3. Roundtrip (WebView to WebView) + +The following steps show how the WebView can get information from the Win32 Host and modify itself by displaying the size of the Win32 App. + +1. Under RoundTrip, click GetWindowBounds + +The box underneath the button should display the bounds for the Sample App. + +Here's how it works: + +1. When the 'Get window bounds' button is clicked, the `GetWindowBounds` function in `ScenarioWebMessage.html` gets called. It uses [window.chrome.webview.postMessage()](https://developer.mozilla.org/docs/Web/API/Window/postMessage) to send a message to the host application. + +```js +function GetWindowBounds() { + window.chrome.webview.postMessage("GetWindowBounds"); + } +``` + +2. Within `ScenarioWebMessage.cpp`, we use [add_WebMessageReceived](https://docs.microsoft.com/microsoft-edge/webview2/reference/win32/icorewebview2#add_webmessagereceived) to register the received event handler. After validating the input, the event handler gets window bounds from the App Window. [PostWebMessageAsJson](https://docs.microsoft.com/microsoft-edge/webview2/reference/win32/icorewebview2#postwebmessageasjson) sends the bounds to the web application. + +```cpp +if (message.compare(L"GetWindowBounds") == 0) +{ + RECT bounds = m_appWindow->GetWindowBounds(); + std::wstring reply = + L"{\"WindowBounds\":\"Left:" + std::to_wstring(bounds.left) + + L"\\nTop:" + std::to_wstring(bounds.top) + + L"\\nRight:" + std::to_wstring(bounds.right) + + L"\\nBottom:" + std::to_wstring(bounds.bottom) + + L"\"}"; + CHECK_FAILURE(sender->PostWebMessageAsJson(reply.c_str())); +} +``` + +3. Within `ScenarioWebMessage.html`, an event listener responds to the WindowBounds message and displays the bounds of the window. + +```js +window.chrome.webview.addEventListener('message', arg => { + if ("WindowBounds" in arg.data) { + document.getElementById("window-bounds").value = arg.data.WindowBounds; + } +}); +``` + +## Code of Conduct + +This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact opencode@microsoft.com with any additional questions or comments. diff --git a/SampleApps/WebView2APISample/ScenarioExtensionsManagement.cpp b/SampleApps/WebView2APISample/ScenarioExtensionsManagement.cpp new file mode 100644 index 00000000..84855f1c --- /dev/null +++ b/SampleApps/WebView2APISample/ScenarioExtensionsManagement.cpp @@ -0,0 +1,34 @@ +// 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 "ScenarioExtensionsManagement.h" + +#include "AppWindow.h" +#include "CheckFailure.h" +#include + +using namespace Microsoft::WRL; + +static constexpr WCHAR c_samplePath[] = L"extensions/example-devtools-extension"; +ScenarioExtensionsManagement::ScenarioExtensionsManagement(AppWindow* appWindow, bool offload) + : m_appWindow(appWindow), m_webView(appWindow->GetWebView()) +{ + if (!offload) + { + InstallDefaultExtensions(); + } + else + { + OffloadDefaultExtensionsIfExtraExtensionsInstalled(); + } +} + +void ScenarioExtensionsManagement::InstallDefaultExtensions() +{ +} +void ScenarioExtensionsManagement::OffloadDefaultExtensionsIfExtraExtensionsInstalled() +{ +} \ No newline at end of file diff --git a/SampleApps/WebView2APISample/ScenarioExtensionsManagement.h b/SampleApps/WebView2APISample/ScenarioExtensionsManagement.h new file mode 100644 index 00000000..4a0c567b --- /dev/null +++ b/SampleApps/WebView2APISample/ScenarioExtensionsManagement.h @@ -0,0 +1,54 @@ +// 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 + +#include "AppWindow.h" +#include "ComponentBase.h" + +class ScenarioExtensionsManagement : public ComponentBase +{ +public: + ScenarioExtensionsManagement(AppWindow* appWindow, bool offload); + +private: + // If this scenario is run, then the user is choosing to install all default extensions. + // Any extension marked as default would be installed if it is not already installed. + // If it is already installed but is disabled, it would be enabled. If it is already + // installed and enabled, then there is no work to be done. The user can also manually + // install any extension marked as default. This scenario is just a way to install and + // enable all default extensions (if not already installed and enabled). + void InstallDefaultExtensions(); + + // If this scenario is run, then the user is choosing to offload default extensions. + // These default extensions would only be removed if there are too many extensions + // installed. In the case of this scenario, "too many extensions" is considered to be more + // than `m_maxInstalledExtensions` which is set to 2, however this is just a simplified way + // to indicate having too many extensions installed. The user can manually remove any + // extensions before running the scenario. When the scenario is run, if the number of + // installed extensions is less than or equal to `m_maxInstalledExtensions`, then none of + // them would be offloaded (regardless of whether any of those extensions are marked as + // default). If more than `m_maxInstalledExtensions` extensions are installed, then all + // default extensions would be offloaded since we have the case of "too many extensions". + void OffloadDefaultExtensionsIfExtraExtensionsInstalled(); + + AppWindow* m_appWindow; + wil::com_ptr m_webViewEnvironment; + wil::com_ptr m_webView; + + // This extension ID is for the "Example DevTools Extension" located under + // assets/extensions. This extension is treated as the default extension for the + // `InstallDefaultExtensions` and `OffloadDefaultExtensionsIfExtraExtensionsInstalled` + // scenarios. + const std::wstring m_extensionId = L"bhjomlfgkfmjffpoikcekmhcblpgefmc"; + + // `m_maxInstalledExtensions` is considered to be the maximum number of extensions we can + // have installed, before we have the case of "too many extensions". If we have too many + // extensions, then the `OffloadDefaultExtensionsIfExtraExtensionsInstalled` scenario + // offloads the default extensions. + const UINT m_maxInstalledExtensions = 2; +}; diff --git a/SampleApps/WebView2APISample/ScriptComponent.cpp b/SampleApps/WebView2APISample/ScriptComponent.cpp index b0945e8b..26866953 100644 --- a/SampleApps/WebView2APISample/ScriptComponent.cpp +++ b/SampleApps/WebView2APISample/ScriptComponent.cpp @@ -9,7 +9,6 @@ #include #include -#include #include "ProcessComponent.h" #include "ScriptComponent.h" diff --git a/SampleApps/WebView2APISample/SettingsComponent.cpp b/SampleApps/WebView2APISample/SettingsComponent.cpp index 739af57f..3fd690bc 100644 --- a/SampleApps/WebView2APISample/SettingsComponent.cpp +++ b/SampleApps/WebView2APISample/SettingsComponent.cpp @@ -745,7 +745,6 @@ bool SettingsComponent::HandleWindowMessage( { //! [TogglePinchZoomEnabled] CHECK_FEATURE_RETURN(m_settings5); - BOOL pinchZoomEnabled; CHECK_FAILURE(m_settings5->get_IsPinchZoomEnabled(&pinchZoomEnabled)); if (pinchZoomEnabled) @@ -907,19 +906,27 @@ bool SettingsComponent::HandleWindowMessage( if (hiddenPdfToolbarItems == COREWEBVIEW2_PDF_TOOLBAR_ITEMS::COREWEBVIEW2_PDF_TOOLBAR_ITEMS_NONE) { - CHECK_FAILURE(m_settings7->put_HiddenPdfToolbarItems( - COREWEBVIEW2_PDF_TOOLBAR_ITEMS::COREWEBVIEW2_PDF_TOOLBAR_ITEMS_PRINT | - COREWEBVIEW2_PDF_TOOLBAR_ITEMS::COREWEBVIEW2_PDF_TOOLBAR_ITEMS_BOOKMARKS | - COREWEBVIEW2_PDF_TOOLBAR_ITEMS::COREWEBVIEW2_PDF_TOOLBAR_ITEMS_FIT_PAGE | - COREWEBVIEW2_PDF_TOOLBAR_ITEMS::COREWEBVIEW2_PDF_TOOLBAR_ITEMS_PAGE_LAYOUT | - COREWEBVIEW2_PDF_TOOLBAR_ITEMS::COREWEBVIEW2_PDF_TOOLBAR_ITEMS_ROTATE | - COREWEBVIEW2_PDF_TOOLBAR_ITEMS::COREWEBVIEW2_PDF_TOOLBAR_ITEMS_SEARCH | - COREWEBVIEW2_PDF_TOOLBAR_ITEMS::COREWEBVIEW2_PDF_TOOLBAR_ITEMS_ZOOM_IN | - COREWEBVIEW2_PDF_TOOLBAR_ITEMS::COREWEBVIEW2_PDF_TOOLBAR_ITEMS_ZOOM_OUT | - COREWEBVIEW2_PDF_TOOLBAR_ITEMS::COREWEBVIEW2_PDF_TOOLBAR_ITEMS_SAVE | - COREWEBVIEW2_PDF_TOOLBAR_ITEMS::COREWEBVIEW2_PDF_TOOLBAR_ITEMS_SAVE_AS | + CHECK_FAILURE( + m_settings7->put_HiddenPdfToolbarItems( + COREWEBVIEW2_PDF_TOOLBAR_ITEMS::COREWEBVIEW2_PDF_TOOLBAR_ITEMS_PRINT | + COREWEBVIEW2_PDF_TOOLBAR_ITEMS:: + COREWEBVIEW2_PDF_TOOLBAR_ITEMS_BOOKMARKS | + COREWEBVIEW2_PDF_TOOLBAR_ITEMS:: + COREWEBVIEW2_PDF_TOOLBAR_ITEMS_FIT_PAGE | + COREWEBVIEW2_PDF_TOOLBAR_ITEMS:: + COREWEBVIEW2_PDF_TOOLBAR_ITEMS_PAGE_LAYOUT | + COREWEBVIEW2_PDF_TOOLBAR_ITEMS::COREWEBVIEW2_PDF_TOOLBAR_ITEMS_ROTATE | + COREWEBVIEW2_PDF_TOOLBAR_ITEMS::COREWEBVIEW2_PDF_TOOLBAR_ITEMS_SEARCH | + COREWEBVIEW2_PDF_TOOLBAR_ITEMS::COREWEBVIEW2_PDF_TOOLBAR_ITEMS_ZOOM_IN | + COREWEBVIEW2_PDF_TOOLBAR_ITEMS:: + COREWEBVIEW2_PDF_TOOLBAR_ITEMS_ZOOM_OUT | + COREWEBVIEW2_PDF_TOOLBAR_ITEMS::COREWEBVIEW2_PDF_TOOLBAR_ITEMS_SAVE | + COREWEBVIEW2_PDF_TOOLBAR_ITEMS::COREWEBVIEW2_PDF_TOOLBAR_ITEMS_SAVE_AS | + COREWEBVIEW2_PDF_TOOLBAR_ITEMS:: + COREWEBVIEW2_PDF_TOOLBAR_ITEMS_PAGE_SELECTOR) | + COREWEBVIEW2_PDF_TOOLBAR_ITEMS::COREWEBVIEW2_PDF_TOOLBAR_ITEMS_FULL_SCREEN | COREWEBVIEW2_PDF_TOOLBAR_ITEMS:: - COREWEBVIEW2_PDF_TOOLBAR_ITEMS_PAGE_SELECTOR)); + COREWEBVIEW2_PDF_TOOLBAR_ITEMS_MORE_SETTINGS); MessageBox( nullptr, L"PDF toolbar print and save buttons are hidden after the next navigation.", @@ -966,6 +973,33 @@ bool SettingsComponent::HandleWindowMessage( //! [ToggleAllowExternalDrop] return true; } + case ID_SETTINGS_SMART_SCREEN_ENABLED: + { + //! [ToggleSmartScreen] + wil::com_ptr experimentalSettings; + experimentalSettings = m_settings.try_query(); + CHECK_FEATURE_RETURN(experimentalSettings); + + BOOL is_smart_screen_enabled; + CHECK_FAILURE(experimentalSettings->get_IsReputationCheckingRequired( + &is_smart_screen_enabled)); + if (is_smart_screen_enabled) + { + CHECK_FAILURE(experimentalSettings->put_IsReputationCheckingRequired(false)); + MessageBox( + nullptr, L"SmartScreen is disable after the next navigation.", + L"Settings change", MB_OK); + } + else + { + CHECK_FAILURE(experimentalSettings->put_IsReputationCheckingRequired(true)); + MessageBox( + nullptr, L"SmartScreen is enable after the next navigation.", + L"Settings change", MB_OK); + } + //! [ToggleSmartScreen] + return true; + } case ID_TOGGLE_CUSTOM_SERVER_CERTIFICATE_SUPPORT: { ToggleCustomServerCertificateSupport(); diff --git a/SampleApps/WebView2APISample/WebView2APISample.rc b/SampleApps/WebView2APISample/WebView2APISample.rc index 09814be1..053d218d 100644 --- a/SampleApps/WebView2APISample/WebView2APISample.rc +++ b/SampleApps/WebView2APISample/WebView2APISample.rc @@ -56,6 +56,7 @@ BEGIN MENUITEM "Get Browser Version After Creation", IDM_GET_BROWSER_VERSION_AFTER_CREATION MENUITEM "Get Browser Version Before Creation", IDM_GET_BROWSER_VERSION_BEFORE_CREATION MENUITEM "Get User Data Folder", IDM_GET_USER_DATA_FOLDER + MENUITEM "Get Failure Report Folder", IDM_GET_FAILURE_REPORT_FOLDER MENUITEM "Update WebView2 Runtime", IDM_UPDATE_RUNTIME MENUITEM "E&xit", IDM_EXIT END @@ -88,6 +89,7 @@ BEGIN MENUITEM "Set WebView Language", IDM_SET_LANGUAGE MENUITEM "Toggle AAD SSO enabled", IDM_TOGGLE_AAD_SSO MENUITEM "Toggle exclusive user data folder access", IDM_TOGGLE_EXCLUSIVE_USER_DATA_FOLDER_ACCESS + MENUITEM "Toggle Custom Crash Reporting" IDM_TOGGLE_CUSTOM_CRASH_REPORTING MENUITEM "Close WebView", IDM_CLOSE_WEBVIEW MENUITEM "Close WebView and Delete User Data Folder", IDM_CLOSE_WEBVIEW_CLEANUP MENUITEM SEPARATOR @@ -134,10 +136,11 @@ BEGIN MENUITEM "Toggle JavaScript", IDM_TOGGLE_JAVASCRIPT MENUITEM "Toggle Password Autosave", ID_SETTINGS_PASSWORD_AUTOSAVE_ENABLED MENUITEM "Toggle Pinch Zoom Enabled", ID_SETTINGS_PINCH_ZOOM_ENABLED + MENUITEM "Toggle Profile Smart Screen", ID_SETTINGS_SMART_SCREEN_ENABLED MENUITEM "Toggle Replace Images", ID_SETTINGS_REPLACEALLIMAGES POPUP "Server Certificate Error" BEGIN - MENUITEM "Toggle Custom Server Certificate Support", ID_TOGGLE_CUSTOM_SERVER_CERTIFICATE_SUPPORT + MENUITEM "Toggle Custom Server Certificate Support", ID_TOGGLE_CUSTOM_SERVER_CERTIFICATE_SUPPORT MENUITEM "Clear Server Certificate Error Actions", ID_CLEAR_SERVER_CERTIFICATE_ERROR_ACTIONS END MENUITEM "Toggle Status Bar Enabled", ID_SETTINGS_STATUS_BAR_ENABLED @@ -243,6 +246,14 @@ BEGIN MENUITEM "Host Objects", IDM_SCENARIO_ADD_HOST_OBJECT MENUITEM "IFrame Device Permission", IDM_SCENARIO_IFRAME_DEVICE_PERMISSION MENUITEM "NavigateWithWebResourceRequest", IDM_SCENARIO_NAVIGATEWITHWEBRESOURCEREQUEST + POPUP "Print" + BEGIN + MENUITEM "Browser Print Preview", IDM_SCENARIO_BROWSER_PRINT_PREVIEW + MENUITEM "System Print", IDM_SCENARIO_SYSTEM_PRINT + MENUITEM "Print to default printer", IDM_SCENARIO_PRINT_TO_DEFAULT_PRINTER + MENUITEM "Print to printer", IDM_SCENARIO_PRINT_TO_PRINTER + MENUITEM "Print to Pdf Stream", IDM_SCENARIO_PRINT_TO_PDF_STREAM + END POPUP "Script Debugging" BEGIN MENUITEM "JavaScript Local File", IDM_SCENARIO_JAVA_SCRIPT @@ -300,10 +311,10 @@ CAPTION "Input" FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN GROUPBOX "Static",IDC_STATIC_LABEL,7,7,295,121 - EDITTEXT IDC_EDIT_INPUT,14,55,281,69,ES_MULTILINE | ES_AUTOHSCROLL + EDITTEXT IDC_EDIT_INPUT,14,55,281,69,ES_MULTILINE | ES_AUTOHSCROLL DEFPUSHBUTTON "OK",IDOK,198,130,50,14 PUSHBUTTON "Cancel",IDCANCEL,252,130,50,14 - EDITTEXT IDC_EDIT_DESCRIPTION,14,18,281,33,ES_MULTILINE | ES_AUTOHSCROLL | ES_READONLY | ES_AUTOVSCROLL | WS_VSCROLL + EDITTEXT IDC_EDIT_DESCRIPTION,14,18,281,33,ES_MULTILINE | ES_AUTOHSCROLL | ES_READONLY | ES_AUTOVSCROLL | WS_VSCROLL END IDD_CERTIFICATE_DIALOG DIALOGEX 0, 0, 375, 175 diff --git a/SampleApps/WebView2APISample/WebView2APISample.vcxproj b/SampleApps/WebView2APISample/WebView2APISample.vcxproj index 46a3086c..38fb98f2 100644 --- a/SampleApps/WebView2APISample/WebView2APISample.vcxproj +++ b/SampleApps/WebView2APISample/WebView2APISample.vcxproj @@ -409,6 +409,7 @@ + @@ -447,6 +448,7 @@ + @@ -555,13 +557,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/documentation/Testing-Instructions.md b/SampleApps/WebView2APISample/documentation/Testing-Instructions.md index 0f37a71e..3cab7e0d 100644 --- a/SampleApps/WebView2APISample/documentation/Testing-Instructions.md +++ b/SampleApps/WebView2APISample/documentation/Testing-Instructions.md @@ -50,6 +50,7 @@ These are instructions for manually testing all the features of the WebView2 API * [Toggle password autosave enabled](#Toggle-password-autosave-enabled) * [Toggle browser accelerator keys enabled](#Toggle-browser-accelerator-keys-enabled) * [Toggle Swipe Navigation enabled](#Toggle-Swipe-Navigation-enabled) + * [Toggle SmartScreen enabled](#Toggle-SmartScreen-enabled) * [Toggle Hidden PDF toolbar items](#Toggle-hide-PDF-toolbar-items) * [Toggle Allow External Drop](#Toggle-Allow-External-Drop) * [Toggle Server Certificate Error](#Toggle-Custom-Server-Certificate-Support) @@ -72,9 +73,13 @@ These are instructions for manually testing all the features of the WebView2 API * [Client Certificate Requested](#ClientCertificateRequested) * [Clear Browsing Data](#ClearBrowsingData) * [Single sign on](#SingleSignOn) + * [Print](#Print) * [IFrame Device Permission](#IFrame-Device-Permission) * [Help](#Help) * [About ...](#about-) + * [Dialogs](#Dialogs) + * [Download Dialog](#Download-Dialog) + * [Find Dialog](#Find-Dialog) * [Miscellaneous](#Miscellaneous) * [Accelerator Key Support](#Accelerator-Key-Support) * [Language](#Language) @@ -707,6 +712,32 @@ _Swipe left/right to navigate is enabled by default._ 1. Click `OK` inside the popup dialog and click `Reload` 1. Verify that swipe to navigate works again. +#### Toggle SmartScreen enabled +Test that enables/disables SmartScreen + +1. Launch the sample app +1. Navigate to +1. Expected: The SmartScreen pop-up window will appear +1. Go to `Settings -> Toggle Profile Smart Screen` +1. Expected: Message Box that says `SmartScreen is disable after the next navigation.` +1. Refresh the page +1. Expected: The popup will no longer appear +1. Go to `Window -> Create New Window` +1. Expected:A new window will be created +1. Navigate both windows to +1. Expected: The SmartScreen pop-up window will appear in both windows +1. In the second window, go to `Settings -> Toggle Profile Smart Screen` +1. Expected: Message Box that says `SmartScreen is disable after the next navigation.` +1. Refresh the pages of both windows. +1. Expected: The pop-up window of SmartScreen will not appear on both windows +1. In the second window,go to `Settings -> Toggle Profile Smart Screen` +1. Expected: Message Box that says `SmartScreen is enable after the next navigation.` +1. Refresh the page +1. Expected: The SmartScreen pop-up window will appear in both windows +1. Close the second window +1. First window navigate to +1. Expected: The popup will no longer appear + #### Toggle hide PDF toolbar items Test that hide/show PDF save button and print button. @@ -1143,6 +1174,25 @@ Test that demonstrates the clear browsing data API. 31. Click on the Name field. 32. Expected: A drop down box with the saved profile information is shown. +#### Print + +Test that demonstrates the ShowPrintUI and Print API. + +1. Launch the sample app. +2. Go to **Scenario** > **Print** > **Browser Print Preview**. +3. Verify that browser print preview dialog is displayed. +4. Click cancel. +5. Go to **Scenario** > **Print** > **System Print**. +6. Verify that system print dialog is displayed. +7. Click cancel. +8. Go to **Scenario** > **Print** > **Print to printer**. +9. On the opened dialog box enter `Microsoft Print to PDF` as the printer name and click OK. +10. Confirm file dialog is displayed. +11. Save the PDF file to a location on the machine. +12. Open and confirm that the sample app home page is printed as PDF without any background graphics. +13. Go to **Scenario** > **Print** > **Print to default printer**. +14. Repeat steps 10-12. + #### IFrame-Device-Permission Test that demonstrates the frame Permission Requested API. @@ -1168,6 +1218,32 @@ Test that gets `About …` 4. Click `OK` inside the popup dialog 5. Expected: dialog closed +### Dialogs +Test that various dialogs work as expected. Uses two windows because some crashes are only caught if the app is still running. + +#### Download Dialog +1. Launch the sample app. +2. Go to `Window -> Create New Thread`. +3. Expected: A new app window is opened. +4. Navigate to https://demo.smartscreen.msft.net. +5. Scroll down to `App Rep Demos` section and click on `Known Good Program` to download. +6. Expected: Download dialog appears. +7. Minimize app window with download dialog. +8. Restore app window with download dialog. +9. Close download dialog using `X` button. +10. Expected: Download dialog is closed. +11. Repeat step 5 to start another download. +12. Close app window with download dialog open. +13. Expected: App window and download dialog are closed. + +#### Find Dialog +1. Launch the sample app. +2. Go to `Window -> Create New Thread`. +3. Expected: A new app window is opened. +4. Launch find dialog on new window with `Ctrl-F`. +5. Close new window. +6. Expected: New window and find dialog are closed. + ### Miscellaneous #### Accelerator Key Support diff --git a/SampleApps/WebView2APISample/documentation/screenshots/sample-app-screenshot.png b/SampleApps/WebView2APISample/documentation/screenshots/sample-app-screenshot.png index 67cd7e58..c891df6d 100644 Binary files a/SampleApps/WebView2APISample/documentation/screenshots/sample-app-screenshot.png and b/SampleApps/WebView2APISample/documentation/screenshots/sample-app-screenshot.png differ diff --git a/SampleApps/WebView2APISample/packages.config b/SampleApps/WebView2APISample/packages.config index 86a2d0db..dbf870c8 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 328da145..253f4c2d 100644 --- a/SampleApps/WebView2APISample/resource.h +++ b/SampleApps/WebView2APISample/resource.h @@ -115,6 +115,8 @@ #define IDC_EDIT_DOWNLOAD_PATH 242 #define IDM_CALL_CDP_METHOD_FOR_SESSION 243 #define IDM_COLLECT_HEAP_MEMORY_VIA_CDP 244 +#define IDM_TOGGLE_CUSTOM_CRASH_REPORTING 246 +#define IDM_GET_FAILURE_REPORT_FOLDER 247 #define IDM_TOGGLE_TOPMOST_WINDOW 300 #define IDE_ADDRESSBAR 1000 #define IDE_ADDRESSBAR_GO 1001 @@ -154,6 +156,11 @@ #define IDM_SCENARIO_CUSTOM_SCHEME 2021 #define IDM_SCENARIO_CUSTOM_SCHEME_NAVIGATE 2022 #define IDM_SCENARIO_SHARED_WORKER 2023 +#define IDM_SCENARIO_BROWSER_PRINT_PREVIEW 2029 +#define IDM_SCENARIO_SYSTEM_PRINT 2030 +#define IDM_SCENARIO_PRINT_TO_DEFAULT_PRINTER 2031 +#define IDM_SCENARIO_PRINT_TO_PRINTER 2032 +#define IDM_SCENARIO_PRINT_TO_PDF_STREAM 2033 #define ID_BLOCKEDSITES 32773 #define ID_SETTINGS_NAVIGATETOSTRING 32774 #define ID_ADD_INITIALIZE_SCRIPT 32775 @@ -178,6 +185,7 @@ #define ID_SETTINGS_TOGGLE_POST_FAVICON_CHANGED 32794 #define ID_TOGGLE_CUSTOM_SERVER_CERTIFICATE_SUPPORT 32797 #define ID_CLEAR_SERVER_CERTIFICATE_ERROR_ACTIONS 32798 +#define ID_SETTINGS_SMART_SCREEN_ENABLED 32799 #define IDC_STATIC -1 // Next default values for new objects // diff --git a/SampleApps/WebView2WindowsFormsBrowser/README.md b/SampleApps/WebView2WindowsFormsBrowser/README.md index 8585079b..63946f70 100644 --- a/SampleApps/WebView2WindowsFormsBrowser/README.md +++ b/SampleApps/WebView2WindowsFormsBrowser/README.md @@ -1,5 +1,5 @@ --- -description: "Demonstrates the features and usage patterns of WebView2 in Windows Forms apps." +description: "Demonstrate the features and usage patterns of WebView2 in Windows Forms." extendedZipContent: - path: SharedContent @@ -14,13 +14,41 @@ products: - microsoft-edge urlFragment: WebView2WindowsFormsBrowser --- -# WinForms sample app +# WebView2 Windows Forms Browser - -This sample, **WebView2WindowsFormsBrowser**, embeds a WebView within a Windows Forms application. +This is a hybrid application built with the [Microsoft Edge WebView2](https://aka.ms/webview2) control. -This sample is built as a Windows Forms Visual Studio project. It uses C# and HTML/CSS/JavaScript in the WebView2 environment. +![Sample App Snapshot](https://raw.githubusercontent.com/MicrosoftEdge/WebView2Samples/master/SampleApps/WebView2WindowsFormsBrowser/screenshots/winforms-browser-screenshot.png) -For more information, see [WinForms sample app](https://docs.microsoft.com/microsoft-edge/webview2/samples/webview2windowsformsbrowser). +The WebView2WindowsFormsBrowser is an example of an application that embeds a WebView within a Windows Forms application. It is built as a Windows Forms [Visual Studio 2019](https://visualstudio.microsoft.com/vs/) project and makes use of both C# and HTML/CSS/JavaScript in the WebView2 environment. -![The WinForms sample app running](screenshots/winforms-browser-screenshot.png) +The API Sample showcases a selection of WebView2's event handlers and API methods that allow a Windows Forms application to directly interact with a WebView and vice versa. + +If this is your first time using WebView, we recommend first following the [Getting Started](https://docs.microsoft.com/microsoft-edge/webview2/gettingstarted/winforms) guide, which goes over how to create a WebView2 and walks through some basic WebView2 functionality. + +To learn more specifics about events and API Handlers in WebView2, you can refer to the [WebView2 Reference Documentation](https://docs.microsoft.com/microsoft-edge/webview2/webview2-api-reference). + +## Prerequisites + +- [Microsoft Edge (Chromium)](https://www.microsoftedgeinsider.com/download/) installed on a supported OS. Currently we recommend the latest version of the Edge Canary channel. +- [Visual Studio](https://visualstudio.microsoft.com/vs/) with .NET support installed. +- Latest pre-release version of our [WebView2 SDK](https://aka.ms/webviewnuget), which is included in this project. + +## Build the WebView2 Windows Forms Browser + +Clone the repository and open the solution in Visual Studio. WebView2 is already included as a NuGet package* in this project. + +- Clone this repository +- Open the solution in Visual Studio 2019** +- Set the target you want to build (Debug/Release, AnyCPU) +- Build the project file: _WebView2WindowsFormsBrowser.csproj_ + +That's it! Everything should be ready to just launch the app. + +*You can get the WebView2 NugetPackage through the Visual Studio NuGet Package Manager. + +**You can also use Visual Studio 2017 by changing the project's Platform Toolset in Project Properties/Configuration properties/General/Platform Toolset. You might also need to change the Windows SDK to the latest version available to you. + +## Code of Conduct + +This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact opencode@microsoft.com with any additional questions or comments. diff --git a/SampleApps/WebView2WindowsFormsBrowser/WebView2WindowsFormsBrowser.csproj b/SampleApps/WebView2WindowsFormsBrowser/WebView2WindowsFormsBrowser.csproj index 261c1117..0fc52b05 100644 --- a/SampleApps/WebView2WindowsFormsBrowser/WebView2WindowsFormsBrowser.csproj +++ b/SampleApps/WebView2WindowsFormsBrowser/WebView2WindowsFormsBrowser.csproj @@ -19,7 +19,7 @@ AnyCPU - + diff --git a/SampleApps/WebView2WpfBrowser/MainWindow.xaml b/SampleApps/WebView2WpfBrowser/MainWindow.xaml index 6d0a4d0d..809e85ac 100644 --- a/SampleApps/WebView2WpfBrowser/MainWindow.xaml +++ b/SampleApps/WebView2WpfBrowser/MainWindow.xaml @@ -43,6 +43,7 @@ found in the LICENSE file. + @@ -63,7 +64,12 @@ found in the LICENSE file. + + + + + @@ -72,6 +78,7 @@ found in the LICENSE file. + @@ -101,6 +108,7 @@ found in the LICENSE file. + @@ -144,6 +152,15 @@ found in the LICENSE file. + + + + + + + + + diff --git a/SampleApps/WebView2WpfBrowser/MainWindow.xaml.cs b/SampleApps/WebView2WpfBrowser/MainWindow.xaml.cs index 7daa93c4..f4ff07d7 100644 --- a/SampleApps/WebView2WpfBrowser/MainWindow.xaml.cs +++ b/SampleApps/WebView2WpfBrowser/MainWindow.xaml.cs @@ -5,6 +5,7 @@ using System; using System.Collections; using System.Collections.Generic; +using System.ComponentModel; using System.Diagnostics; using System.IO; using System.Linq; @@ -42,6 +43,7 @@ public partial class MainWindow : Window public static RoutedCommand CheckUpdateCommand = new RoutedCommand(); public static RoutedCommand NewBrowserVersionCommand = new RoutedCommand(); public static RoutedCommand PdfToolbarSaveCommand = new RoutedCommand(); + public static RoutedCommand SmartScreenEnabledCommand = new RoutedCommand(); public static RoutedCommand AuthenticationCommand = new RoutedCommand(); public static RoutedCommand FaviconChangedCommand = new RoutedCommand(); public static RoutedCommand ClearBrowsingDataCommand = new RoutedCommand(); @@ -66,8 +68,13 @@ public partial class MainWindow : Window public static RoutedCommand CustomServerCertificateSupportCommand = new RoutedCommand(); public static RoutedCommand ClearServerCertificateErrorActionsCommand = new RoutedCommand(); public static RoutedCommand NewWindowWithOptionsCommand = new RoutedCommand(); + public static RoutedCommand PrintDialogCommand = new RoutedCommand(); + public static RoutedCommand PrintToDefaultPrinterCommand = new RoutedCommand(); + public static RoutedCommand PrintToPrinterCommand = new RoutedCommand(); + public static RoutedCommand PrintToPdfStreamCommand = new RoutedCommand(); // Commands(V2) public static RoutedCommand AboutCommand = new RoutedCommand(); + public static RoutedCommand GetDocumentTitleCommand = new RoutedCommand(); bool _isNavigating = false; CoreWebView2Settings _webViewSettings; @@ -120,7 +127,7 @@ public MainWindow() InitializeComponent(); AttachControlEventHandlers(webView); // Set background transparent - webView.DefaultBackgroundColor = System.Drawing.Color.Transparent; + // webView.DefaultBackgroundColor = System.Drawing.Color.Transparent; } public MainWindow(CoreWebView2CreationProperties creationProperties = null) @@ -130,7 +137,7 @@ public MainWindow(CoreWebView2CreationProperties creationProperties = null) InitializeComponent(); AttachControlEventHandlers(webView); // Set background transparent - webView.DefaultBackgroundColor = System.Drawing.Color.Transparent; + // webView.DefaultBackgroundColor = System.Drawing.Color.Transparent; } void AttachControlEventHandlers(WebView2 control) @@ -247,6 +254,26 @@ void ClearServerCertificateErrorActionsCmdExecuted(object target, ExecutedRouted ClearServerCertificateErrorActions(); } + void PrintDialogCmdExecuted(object target, ExecutedRoutedEventArgs e) + { + ShowPrintUI(target, e); + } + + void PrintToDefaultPrinterCmdExecuted(object target, ExecutedRoutedEventArgs e) + { + PrintToDefaultPrinter(); + } + + void PrintToPrinterCmdExecuted(object target, ExecutedRoutedEventArgs e) + { + PrintToPrinter(); + } + + void PrintToPdfStreamCmdExecuted(object target, ExecutedRoutedEventArgs e) + { + PrintToPdfStream(); + } + private bool _isControlInVisualTree = true; void RemoveControlFromVisualTree(WebView2 control) @@ -539,6 +566,163 @@ async void PrintToPdfCmdExecuted(object target, ExecutedRoutedEventArgs e) } } + // Shows the user a print dialog. If `printDialogKind` is browser print preview, + // opens a browser print preview dialog, CoreWebView2PrintDialogKind.System opens a system print dialog. + void ShowPrintUI(object target, ExecutedRoutedEventArgs e) + { + string printDialog = e.Parameter.ToString(); + if (printDialog == "Browser") + { + // Opens the browser print preview dialog. + webView.CoreWebView2.ShowPrintUI(); + } + else + { + // Opens the system print dialog. + webView.CoreWebView2.ShowPrintUI(CoreWebView2PrintDialogKind.System); + } + } + + // This example prints the current web page without a print dialog to default printer. + async void PrintToDefaultPrinter () + { + string title = webView.CoreWebView2.DocumentTitle; + + try + { + // Passing null for `PrintSettings` results in default print settings used. + // Prints current web page with the default page and printer settings. + CoreWebView2PrintStatus printStatus = await webView.CoreWebView2.PrintAsync(null); + + if (printStatus == CoreWebView2PrintStatus.Succeeded) + { + MessageBox.Show(this, "Printing " + title + " document to printer is succeeded", "Print"); + } + else if (printStatus == CoreWebView2PrintStatus.PrinterUnavailable) + { + MessageBox.Show(this, "Printer is not available, offline or error state", "Print"); + } + else + { + MessageBox.Show(this, "Printing " + title + " document to printer is failed", + "Print"); + } + } + catch (Exception) + { + MessageBox.Show(this, "Printing " + title + " document already in progress", + "Print"); + } + } + + // Function to get printer name by displaying printer text input dialog to the user. + // User has to specify the desired printer name by querying the installed printers list on the + // OS to print the web page. + // You may also choose to display printers list to the user and return user selected printer. + string GetPrinterName() + { + string printerName = ""; + + var dialog = new TextInputDialog( + title: "Printer Name", + description: "Specify a printer name from the installed printers list on the OS.", + defaultInput: ""); + if (dialog.ShowDialog() == true) + { + printerName = dialog.Input.Text; + } + return printerName; + + // or + // + // Use GetPrintQueues() of LocalPrintServer from System.Printing to get list of locally installed printers. + // Display the printer list to the user and get the desired printer to print. + // Return the user selected printer name. + } + + // Function to get print settings for the selected printer. + // You may also choose get the capabilties from the native printer API, display to the user to get + // the print settings for the current web page and for the selected printer. + CoreWebView2PrintSettings GetSelectedPrinterPrintSettings(string printerName) + { + CoreWebView2PrintSettings printSettings = null; + printSettings = WebViewEnvironment.CreatePrintSettings(); + printSettings.ShouldPrintBackgrounds = true; + printSettings.ShouldPrintHeaderAndFooter = true; + + return printSettings; + + // or + // + // Get PrintQueue for the selected printer and use GetPrintCapabilities() of PrintQueue from System.Printing + // to get the capabilities of the selected printer. + // Display the printer capabilities to the user along with the page settings. + // Return the user selected settings. + } + + // This example prints the current web page to the specified printer with the settings. + async void PrintToPrinter() + { + string printerName = GetPrinterName(); + CoreWebView2PrintSettings printSettings = GetSelectedPrinterPrintSettings(printerName); + string title = webView.CoreWebView2.DocumentTitle; + try + { + CoreWebView2PrintStatus printStatus = await webView.CoreWebView2.PrintAsync(printSettings); + + if (printStatus == CoreWebView2PrintStatus.Succeeded) + { + MessageBox.Show(this, "Printing " + title + " document to printer is succeeded", "Print to printer"); + } + else if (printStatus == CoreWebView2PrintStatus.PrinterUnavailable) + { + MessageBox.Show(this, "Selected printer is not found, not available, offline or error state", "Print to printer"); + } + else + { + MessageBox.Show(this, "Printing " + title + " document to printer is failed", + "Print"); + } + } + catch(ArgumentException) + { + MessageBox.Show(this, "Invalid settings provided for the specified printer", + "Print"); + } + catch (Exception) + { + MessageBox.Show(this, "Printing " + title + " document already in progress", + "Print"); + + } + } + + // This example prints the Pdf data of the current web page to a stream. + async void PrintToPdfStream() + { + try + { + string title = webView.CoreWebView2.DocumentTitle; + + // Passing null for `PrintSettings` results in default print settings used. + System.IO.Stream stream = await webView.CoreWebView2.PrintToPdfStreamAsync(null); + + DisplayPdfDataInPrintDialog(stream); + MessageBox.Show(this, "Printing" + title + " document to PDF Stream " + ((stream != null) ? "succeeded" : "failed"), "Print To PDF Stream"); + } + catch (Exception exception) + { + MessageBox.Show(this, "Printing to PDF Stream failed: " + exception.Message, + "Print to PDF Stream"); + } + } + + // Function to display current page pdf data in a custom print preview dialog. + void DisplayPdfDataInPrintDialog(Stream pdfData) + { + // You can display the printable pdf data in a custom print preview dialog to the end user. + } + async void GetCookiesCmdExecuted(object target, ExecutedRoutedEventArgs e) { // @@ -1476,6 +1660,10 @@ private string GetRuntimePath(CoreWebView2 webView2) { return e.Message; } + catch (Win32Exception) + { + return "N/A"; + } } private string GetStartPageUri(CoreWebView2 webView2) @@ -1909,11 +2097,23 @@ void NewWindowWithOptionsCmdExecuted(object target, ExecutedRoutedEventArgs e) new MainWindow(dialog.CreationProperties).Show(); } } - // Commands(V2) void AboutCommandExecuted(object target, ExecutedRoutedEventArgs e) { MessageBox.Show(this, "WebView2WpfBrowser, Version 1.0\nCopyright(C) 2022", "About WebView2WpfBrowser"); } + + private void SmartScreenEnabledExecuted(object sender, ExecutedRoutedEventArgs e) + { + // + WebViewSettings.IsReputationCheckingRequired = !WebViewSettings.IsReputationCheckingRequired; + // + MessageBox.Show("SmartScreen is" + (WebViewSettings.IsReputationCheckingRequired ? " enabled " : " disabled ") + "after the next navigation."); + } + + void GetDocumentTitleCommandExecuted(object target, ExecutedRoutedEventArgs e) + { + MessageBox.Show(webView.CoreWebView2.DocumentTitle, "Document Title"); + } } } diff --git a/SampleApps/WebView2WpfBrowser/README.md b/SampleApps/WebView2WpfBrowser/README.md index 4359b086..48ed97e1 100644 --- a/SampleApps/WebView2WpfBrowser/README.md +++ b/SampleApps/WebView2WpfBrowser/README.md @@ -1,5 +1,5 @@ --- -description: "Demonstrates the features and usage patterns of WebView2 in WPF apps." +description: "Demonstrate the features and usage patterns of WebView2 in WPF." extendedZipContent: - path: SharedContent @@ -14,13 +14,45 @@ products: - microsoft-edge urlFragment: WebView2WpfBrowser --- -# WPF sample app +# WebView2 WPF Browser - -This sample, **WebView2WpfBrowser**, embeds a WebView2 control within a WPF application. +This is a hybrid application built with the [Microsoft Edge WebView2](https://aka.ms/webview2) control. -This sample is built as a WPF Visual Studio 2019 project. It uses C# and HTML/CSS/JavaScript in the WebView2 environment. +![Sample App Snapshot](https://raw.githubusercontent.com/MicrosoftEdge/WebView2Samples/master/SampleApps/WebView2WpfBrowser/screenshots/wpf-browser-screenshot.png) -For more information, see [WPF sample app](https://docs.microsoft.com/microsoft-edge/webview2/samples/webview2wpfbrowser). +The WebView2WpfBrowser is an example of an application that embeds a WebView within a WPF application. It is built as a WPF [Visual Studio 2019](https://visualstudio.microsoft.com/vs/) project and makes use of both C# and HTML/CSS/JavaScript in the WebView2 environment. -![The WPF sample app running](screenshots/wpf-browser-screenshot.png) +The API Sample showcases a selection of WebView2's event handlers and API methods that allow a WPF application to directly interact with a WebView and vice versa. + +If this is your first time using WebView, we recommend first following the [Getting Started](https://docs.microsoft.com/microsoft-edge/webview2/gettingstarted/wpf) guide, which goes over how to create a WebView2 and walks through some basic WebView2 functionality. + +To learn more specifics about events and API Handlers in WebView2, you can refer to the [WebView2 Reference Documentation](https://docs.microsoft.com/microsoft-edge/webview2/webview2-api-reference). + +## Prerequisites + +- [Microsoft Edge (Chromium)](https://www.microsoftedgeinsider.com/download/) installed on a supported OS. Currently we recommend the latest version of the Edge Canary channel. +- [Visual Studio](https://visualstudio.microsoft.com/vs/) with .NET support installed. +- Latest pre-release version of our [WebView2 SDK](https://aka.ms/webviewnuget), which is included in this project. + +## Build the WebView2 WPF Browser + +Clone the repository and open the solution in Visual Studio. WebView2 is already included as a NuGet package* in this project. + +- Clone this repository +- Open the solution in Visual Studio 2019** +- Set the target you want to build (Debug/Release, AnyCPU) +- Build the project file: _WebView2WpfBrowser.csproj_ + +That's it! Everything should be ready to just launch the app. + +*You can get the WebView2 NugetPackage through the Visual Studio NuGet Package Manager. + +**You can also use Visual Studio 2017 by changing the project's Platform Toolset in Project Properties/Configuration properties/General/Platform Toolset. You might also need to change the Windows SDK to the latest version available to you. + +## Using Fixed version + +If you want to use [fixed version](https://docs.microsoft.com/en-us/microsoft-edge/webview2/concepts/distribution#fixed-version-distribution-mode), i.e. Bring-Your-Own (BYO), follow the instructions in MainWindow.xaml and App.xaml. + +## Code of Conduct + +This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact opencode@microsoft.com with any additional questions or comments. diff --git a/SampleApps/WebView2WpfBrowser/WebView2WpfBrowser.csproj b/SampleApps/WebView2WpfBrowser/WebView2WpfBrowser.csproj index cc588a89..9c68f20f 100644 --- a/SampleApps/WebView2WpfBrowser/WebView2WpfBrowser.csproj +++ b/SampleApps/WebView2WpfBrowser/WebView2WpfBrowser.csproj @@ -40,6 +40,6 @@ - + \ No newline at end of file