diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 0bc8d0bb4..74f5b3ac8 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -72,5 +72,27 @@ jobs: - name: Restore run: dotnet restore "Source/Krypton Components/Krypton Toolkit Suite 2022 - VS2022.sln" + - name: Setup WebView2 SDK + run: | + # Create WebView2SDK directory + mkdir WebView2SDK + # Get latest WebView2 SDK version + $packageId = "Microsoft.Web.WebView2" + $apiUrl = "https://api.nuget.org/v3-flatcontainer/$packageId/index.json" + $response = Invoke-RestMethod -Uri $apiUrl -Method Get + $versions = $response.versions | Sort-Object { [Version]$_ } -Descending + $stableVersions = $versions | Where-Object { $_ -notmatch '[-]' } + $latestVersion = $stableVersions[0] + Write-Host "Using WebView2 SDK version: $latestVersion" + # Download WebView2 SDK assemblies using NuGet + dotnet add "Source/Krypton Components/Krypton.Toolkit/Krypton.Toolkit 2022.csproj" package Microsoft.Web.WebView2 --version $latestVersion --no-restore + # Copy assemblies to WebView2SDK directory + $nugetPath = "$env:USERPROFILE\.nuget\packages\microsoft.web.webview2\$latestVersion\lib\net45" + Copy-Item "$nugetPath\Microsoft.Web.WebView2.Core.dll" "WebView2SDK\" + Copy-Item "$nugetPath\Microsoft.Web.WebView2.WinForms.dll" "WebView2SDK\" + Copy-Item "$nugetPath\WebView2Loader.dll" "WebView2SDK\" + # Remove NuGet package reference + dotnet remove "Source/Krypton Components/Krypton.Toolkit/Krypton.Toolkit 2022.csproj" package Microsoft.Web.WebView2 + - name: Build run: msbuild "Scripts/nightly.proj" /t:Rebuild /p:Configuration=Release /p:Platform="Any CPU" diff --git a/Documents/Changelog/Changelog.md b/Documents/Changelog/Changelog.md index 732427446..fdfe9be07 100644 --- a/Documents/Changelog/Changelog.md +++ b/Documents/Changelog/Changelog.md @@ -3,6 +3,7 @@ ==== ## 2025-11-xx - Build 2511 (V10 - alpha) - November 2025 +* Implemented [#1026](https://github.com/Krypton-Suite/Standard-Toolkit/issues/1026), Krypton version of `WebView2` * Resolved [#2492](https://github.com/Krypton-Suite/Standard-Toolkit/issues/2492), `KryptonForm` does not display '(Administrator)' when elevated * Resolved [#2502](https://github.com/Krypton-Suite/Standard-Toolkit/issues/2502), **[Breaking Change]** `KryptonCommandLinkButton` updates several properties and their behaviour. See issue for full details. * Resolved [#2495](https://github.com/Krypton-Suite/Standard-Toolkit/issues/2495), `KryptonProgressBar` private field `_mementoContent` can be null. diff --git a/Documents/WebView2SDK-Setup.md b/Documents/WebView2SDK-Setup.md new file mode 100644 index 000000000..66e0ef951 --- /dev/null +++ b/Documents/WebView2SDK-Setup.md @@ -0,0 +1,182 @@ +# WebView2 SDK Setup for KryptonWebView2 + +## Overview + +The KryptonWebView2 control requires the Microsoft WebView2 SDK assemblies to be available for compilation. This document explains how to set up the WebView2 SDK without using NuGet dependencies. + +**Quick Start**: Run `run.cmd` and select option 7 "WebView2 SDK Tools" → option 1 "Setup WebView2 SDK" for automated setup. + +**Latest Version**: The setup automatically detects and uses the latest stable WebView2 SDK version from NuGet. + +## Setup Options + +### Option 1: Manual Download (Recommended) + +1. **Download WebView2 SDK** + - Visit: https://developer.microsoft.com/en-us/microsoft-edge/webview2/ + - Download the latest WebView2 SDK + - Extract the downloaded package + +2. **Copy Required Assemblies** + - Create a `WebView2SDK` folder at the repository root (same level as `Source` folder) + - Copy the following files from the extracted SDK to `WebView2SDK`: + ``` + WebView2SDK/ + ├── Microsoft.Web.WebView2.Core.dll + ├── Microsoft.Web.WebView2.WinForms.dll + └── WebView2Loader.dll + ``` + +3. **Build the Solution** + - Rebuild the entire solution + - The KryptonWebView2 control should now compile successfully + +### Option 2: Using NuGet (Temporary) + +If you want to quickly get the assemblies without manual download: + +1. **Install NuGet Package** + ```cmd + dotnet add package Microsoft.Web.WebView2 + ``` + +2. **Copy Assemblies** + - Find the NuGet packages folder (usually `%USERPROFILE%\.nuget\packages\`) + - Navigate to the latest version folder (e.g., `microsoft.web.webview2\1.0.3485.44\lib\net45\`) + - Copy the required DLLs to the `WebView2SDK` folder + - Remove the NuGet package reference if desired + +3. **Clean Up** + ```cmd + dotnet remove package Microsoft.Web.WebView2 + ``` + +### Option 3: Using Setup Script (Recommended) + +#### Method A: Through Build System Menu +1. **Run the Build System** + ```cmd + run.cmd + ``` +2. **Select Option 7**: "WebView2 SDK Tools" +3. **Select Option 1**: "Setup WebView2 SDK" +4. **Follow the automated process** + +#### Method B: Direct Script Execution +Run the provided setup script directly: +```cmd +Setup-WebView2SDK.cmd +``` + +Both methods will: +- Check if WebView2 SDK is already installed +- Automatically detect the latest stable WebView2 SDK version +- Download and install WebView2 SDK via NuGet (if needed) +- Copy required assemblies to the WebView2SDK directory +- Update project file with the latest version information +- Clean up temporary NuGet references +- Provide clear feedback on the setup status + +### Option 4: Update to Latest Version + +If you already have WebView2 SDK installed and want to update to the latest version: + +#### Method A: Through Build System Menu +1. **Run the Build System** + ```cmd + run.cmd + ``` +2. **Select Option 7**: "WebView2 SDK Tools" +3. **Select Option 2**: "Update WebView2 SDK" +4. **Follow the automated update process** + +#### Method B: Direct Script Execution +Run the update script directly: +```cmd +Scripts\Update-WebView2SDK.cmd +``` + +Both methods will: +- Detect the latest stable WebView2 SDK version +- Download the latest assemblies +- Update the WebView2SDK directory +- Update project file references +- Preserve your existing setup + +## File Structure After Setup + +Your repository should look like this: +``` +Standard-Toolkit/ +├── Source/ +│ └── Krypton Components/ +│ └── Krypton.Toolkit/ +│ └── Controls Toolkit/ +│ └── KryptonWebView2.cs +├── Scripts/ +│ ├── Setup-WebView2SDK.cmd +│ ├── Update-WebView2SDK.cmd +│ ├── Get-LatestWebView2Version.ps1 +│ └── Update-WebView2ProjectVersion.ps1 +├── WebView2SDK/ ← Created by setup script +│ ├── Microsoft.Web.WebView2.Core.dll +│ ├── Microsoft.Web.WebView2.WinForms.dll +│ └── WebView2Loader.dll +└── run.cmd ← Updated with WebView2 SDK Tools submenu +``` + +## Verification + +After setup, verify that the KryptonWebView2 control compiles: + +1. **Build the Solution** + ```cmd + dotnet build "Source/Krypton Components/Krypton Toolkit Suite 2022 - VS2022.sln" + ``` + +2. **Check for Errors** + - No compilation errors related to WebView2 types + - KryptonWebView2 appears in the toolbox + - Test form compiles successfully + +## Troubleshooting + +### "WebView2 types not found" Error +- Ensure the WebView2SDK folder exists at the repository root +- Verify all three DLL files are present in WebView2SDK +- Check that the project file references point to the correct paths +- Rebuild the solution completely + +### Assembly Loading Errors +- Ensure the DLLs are the correct architecture (AnyCPU or x64) +- Check that the DLLs are not corrupted +- Verify the file permissions allow reading + +### Designer Issues +- Reset the Visual Studio toolbox +- Close and reopen Visual Studio +- Ensure the control compiles without errors first + +## Runtime Requirements + +Remember that end users need the WebView2 Runtime installed: + +- **Evergreen Distribution**: Users install from Microsoft's website +- **Fixed Version**: Bundle with your application +- **Download**: https://developer.microsoft.com/en-us/microsoft-edge/webview2/ + +## Support + +If you encounter issues: + +1. Check the WebView2 documentation: https://docs.microsoft.com/en-us/microsoft-edge/webview2/ +2. Verify your setup matches the requirements +3. Test with the provided KryptonWebView2Test form +4. Report issues to the Krypton Toolkit repository + +## Notes + +- The WebView2SDK folder should be added to `.gitignore` if you don't want to commit the assemblies +- The assemblies are referenced with `Private=False` so they won't be copied to output +- This setup allows the control to compile without NuGet dependencies +- Runtime WebView2 functionality requires the WebView2 Runtime to be installed on target systems diff --git a/Scripts/Check-WebView2Version.cmd b/Scripts/Check-WebView2Version.cmd new file mode 100644 index 000000000..6277b67da --- /dev/null +++ b/Scripts/Check-WebView2Version.cmd @@ -0,0 +1,19 @@ +@echo off +echo Checking WebView2 SDK version... +echo. + +if exist "WebView2SDK\Microsoft.Web.WebView2.Core.dll" ( + echo Current installed version: + powershell -Command "Get-ItemProperty 'WebView2SDK\Microsoft.Web.WebView2.Core.dll' | Select-Object -ExpandProperty VersionInfo | Select-Object -ExpandProperty FileVersion" + echo. + echo Latest available version: + powershell -ExecutionPolicy Bypass -File "%~dp0Get-LatestWebView2Version.ps1" +) else ( + echo WebView2 SDK is not installed. + echo. + echo Latest available version: + powershell -ExecutionPolicy Bypass -File "%~dp0Get-LatestWebView2Version.ps1" +) + +echo. +pause diff --git a/Scripts/Get-LatestWebView2Version.ps1 b/Scripts/Get-LatestWebView2Version.ps1 new file mode 100644 index 000000000..81fb99936 --- /dev/null +++ b/Scripts/Get-LatestWebView2Version.ps1 @@ -0,0 +1,41 @@ +# Get-LatestWebView2Version.ps1 +# Script to get the latest stable version of Microsoft.Web.WebView2 from NuGet + +param( + [switch]$Prerelease = $false +) + +try { + # Use NuGet API to get package information + $packageId = "Microsoft.Web.WebView2" + $apiUrl = "https://api.nuget.org/v3-flatcontainer/$packageId/index.json" + + Write-Host "Fetching latest version information for $packageId..." -ForegroundColor Green + + # Get package versions + $response = Invoke-RestMethod -Uri $apiUrl -Method Get + + if ($Prerelease) { + # Include prerelease versions - sort by version number only + $versions = $response.versions | Where-Object { $_ -match '^\d+\.\d+\.\d+' } | + Sort-Object { [Version]($_ -replace '-.*$', '') } -Descending + $latestVersion = $versions[0] + } else { + # Only stable versions (no prerelease identifiers) + $stableVersions = $response.versions | Where-Object { $_ -notmatch '[-]' } | + Sort-Object { [Version]$_ } -Descending + $latestVersion = $stableVersions[0] + } + + if ($latestVersion) { + Write-Host "Latest version: $latestVersion" -ForegroundColor Yellow + return $latestVersion + } else { + Write-Error "No suitable version found" + return $null + } +} +catch { + Write-Error "Failed to fetch version information: $($_.Exception.Message)" + return $null +} diff --git a/Scripts/Setup-WebView2SDK.cmd b/Scripts/Setup-WebView2SDK.cmd new file mode 100644 index 000000000..75afff57b --- /dev/null +++ b/Scripts/Setup-WebView2SDK.cmd @@ -0,0 +1,90 @@ +@echo off +echo Setting up WebView2 SDK for KryptonWebView2 control... +echo. + +REM Check if WebView2SDK directory exists and has the required files +if exist "WebView2SDK\Microsoft.Web.WebView2.Core.dll" ( + if exist "WebView2SDK\Microsoft.Web.WebView2.WinForms.dll" ( + if exist "WebView2SDK\WebView2Loader.dll" ( + echo WebView2 SDK assemblies are already present! + echo. + echo Files found: + dir WebView2SDK\*.dll + echo. + echo The KryptonWebView2 control should compile successfully. + echo You can now build the solution and use the control. + echo. + pause + exit /b 0 + ) + ) +) + +REM Create WebView2SDK directory if it doesn't exist +if not exist "WebView2SDK" ( + echo Creating WebView2SDK directory... + mkdir WebView2SDK +) + +echo. +echo WebView2 SDK assemblies are missing. Setting up automatically... +echo. + +REM Get the latest WebView2 SDK version +echo Detecting latest WebView2 SDK version... +powershell -ExecutionPolicy Bypass -File "%~dp0Get-LatestWebView2Version.ps1" > temp_version.txt 2>&1 +set /p WEBVIEW2_VERSION=nul 2>&1 + copy "%USERPROFILE%\.nuget\packages\microsoft.web.webview2\%WEBVIEW2_VERSION%\lib\net45\Microsoft.Web.WebView2.WinForms.dll" "WebView2SDK\" >nul 2>&1 + copy "%USERPROFILE%\.nuget\packages\microsoft.web.webview2\%WEBVIEW2_VERSION%\runtimes\win-x64\native\WebView2Loader.dll" "WebView2SDK\" >nul 2>&1 + + REM Remove the NuGet package reference since we're using local assemblies + dotnet remove "Source/Krypton Components/Krypton.Toolkit/Krypton.Toolkit 2022.csproj" package Microsoft.Web.WebView2 + + REM Update project file with the latest version + echo Updating project file with latest version... + powershell -ExecutionPolicy Bypass -File "%~dp0Update-WebView2ProjectVersion.ps1" + + echo. + echo WebView2 SDK setup completed successfully! + echo. + echo Installed version: %WEBVIEW2_VERSION% + echo Files copied: + dir WebView2SDK\*.dll + echo. + echo You can now build the solution and use the KryptonWebView2 control. +) else ( + echo. + echo Automatic setup failed. Please follow manual setup instructions: + echo. + echo MANUAL SETUP INSTRUCTIONS: + echo 1. Download the WebView2 SDK from: https://developer.microsoft.com/en-us/microsoft-edge/webview2/ + echo 2. Extract the following files to the WebView2SDK folder: + echo - Microsoft.Web.WebView2.Core.dll + echo - Microsoft.Web.WebView2.WinForms.dll + echo - WebView2Loader.dll + echo. + echo Alternative: Use NuGet Package Manager to install Microsoft.Web.WebView2 + echo and copy the assemblies from the packages folder to WebView2SDK. +) + +echo. +pause diff --git a/Scripts/Update-WebView2ProjectVersion.ps1 b/Scripts/Update-WebView2ProjectVersion.ps1 new file mode 100644 index 000000000..107c0a687 --- /dev/null +++ b/Scripts/Update-WebView2ProjectVersion.ps1 @@ -0,0 +1,84 @@ +# Update-WebView2ProjectVersion.ps1 +# Script to update the project file with the latest WebView2 SDK version + +param( + [string]$ProjectPath = "Source/Krypton Components/Krypton.Toolkit/Krypton.Toolkit 2022.csproj", + [switch]$WhatIf = $false +) + +function Get-LatestWebView2Version { + try { + $packageId = "Microsoft.Web.WebView2" + $apiUrl = "https://api.nuget.org/v3-flatcontainer/$packageId/index.json" + + Write-Host "Fetching latest version information for $packageId..." -ForegroundColor Green + + $response = Invoke-RestMethod -Uri $apiUrl -Method Get + + # Only stable versions (no prerelease identifiers) + $stableVersions = $response.versions | Where-Object { $_ -notmatch '[-]' } | + Sort-Object { [Version]$_ } -Descending + $latestVersion = $stableVersions[0] + + if ($latestVersion) { + Write-Host "Latest stable version: $latestVersion" -ForegroundColor Yellow + return $latestVersion + } else { + Write-Error "No stable version found" + return $null + } + } + catch { + Write-Error "Failed to fetch version information: $($_.Exception.Message)" + return $null + } +} + +function Update-ProjectFile { + param( + [string]$ProjectPath, + [string]$NewVersion, + [switch]$WhatIf + ) + + if (-not (Test-Path $ProjectPath)) { + Write-Error "Project file not found: $ProjectPath" + return $false + } + + $content = Get-Content $ProjectPath -Raw + + # Update .NET Framework references + $netFrameworkPattern = 'Microsoft\.Web\.WebView2\.Core, Version=([^,]+), Culture=neutral' + $netFrameworkReplacement = "Microsoft.Web.WebView2.Core, Version=$NewVersion, Culture=neutral" + + $updatedContent = $content -replace $netFrameworkPattern, $netFrameworkReplacement + + if ($updatedContent -ne $content) { + if ($WhatIf) { + Write-Host "Would update project file with version $NewVersion" -ForegroundColor Cyan + } else { + Set-Content $ProjectPath $updatedContent -NoNewline + Write-Host "Updated project file with version $NewVersion" -ForegroundColor Green + } + return $true + } else { + Write-Warning "No version references found to update in project file" + return $false + } +} + +# Main execution +$latestVersion = Get-LatestWebView2Version + +if ($latestVersion) { + $updated = Update-ProjectFile -ProjectPath $ProjectPath -NewVersion $latestVersion -WhatIf:$WhatIf + + if ($updated -and -not $WhatIf) { + Write-Host "Project file updated successfully!" -ForegroundColor Green + Write-Host "You may need to rebuild the solution for changes to take effect." -ForegroundColor Yellow + } +} else { + Write-Error "Could not determine latest WebView2 version" + exit 1 +} diff --git a/Scripts/Update-WebView2SDK.cmd b/Scripts/Update-WebView2SDK.cmd new file mode 100644 index 000000000..33d16c3fe --- /dev/null +++ b/Scripts/Update-WebView2SDK.cmd @@ -0,0 +1,69 @@ +@echo off +echo Updating to latest WebView2 SDK version... +echo. + +REM Check if WebView2SDK directory exists +if not exist "WebView2SDK" ( + echo WebView2SDK directory not found. Please run Setup-WebView2SDK.cmd first. + echo. + pause + exit /b 1 +) + +REM Get the latest WebView2 SDK version +echo Detecting latest WebView2 SDK version... +powershell -ExecutionPolicy Bypass -File "%~dp0Get-LatestWebView2Version.ps1" > temp_version.txt 2>&1 +set /p WEBVIEW2_VERSION=nul 2>&1 + copy "%USERPROFILE%\.nuget\packages\microsoft.web.webview2\%WEBVIEW2_VERSION%\lib\net45\Microsoft.Web.WebView2.WinForms.dll" "WebView2SDK\" >nul 2>&1 + copy "%USERPROFILE%\.nuget\packages\microsoft.web.webview2\%WEBVIEW2_VERSION%\runtimes\win-x64\native\WebView2Loader.dll" "WebView2SDK\" >nul 2>&1 + + REM Remove the NuGet package reference + dotnet remove "Source/Krypton Components/Krypton.Toolkit/Krypton.Toolkit 2022.csproj" package Microsoft.Web.WebView2 + + REM Update project file with the latest version + echo Updating project file with latest version... + powershell -ExecutionPolicy Bypass -File "%~dp0Update-WebView2ProjectVersion.ps1" + + echo. + echo WebView2 SDK updated successfully! + echo. + echo Installed version: %WEBVIEW2_VERSION% + echo Updated files: + dir WebView2SDK\*.dll + echo. + echo You may need to rebuild the solution for changes to take effect. +) else ( + echo. + echo Failed to update WebView2 SDK. Please check your internet connection and try again. +) + +echo. +pause diff --git a/Source/Krypton Components/Krypton.Toolkit/Controls Toolkit/KryptonWebView2.cs b/Source/Krypton Components/Krypton.Toolkit/Controls Toolkit/KryptonWebView2.cs new file mode 100644 index 000000000..8917238f6 --- /dev/null +++ b/Source/Krypton Components/Krypton.Toolkit/Controls Toolkit/KryptonWebView2.cs @@ -0,0 +1,419 @@ +#region BSD License +/* + * + * Original BSD 3-Clause License (https://github.com/ComponentFactory/Krypton/blob/master/LICENSE) + * © Component Factory Pty Ltd, 2006 - 2016, (Version 4.5.0.0) All rights reserved. + * + * New BSD 3-Clause License (https://github.com/Krypton-Suite/Standard-Toolkit/blob/master/LICENSE) + * Modifications by Peter Wagner (aka Wagnerp), Simon Coghlan (aka Smurf-IV), Giduac & Ahmed Abdelhameed, tobitege et al. 2025 - 2025. All rights reserved. + * + */ +#endregion + +#if WEBVIEW2_AVAILABLE +// Do not remove this using statement, it is used for the WebView2 control +using Microsoft.Web.WebView2.WinForms; +#endif + +namespace Krypton.Toolkit; + +#if WEBVIEW2_AVAILABLE +/// +/// Provide a WebView2 control with Krypton styling applied. +/// +/// +/// KryptonWebView2 is a modern web browser control that integrates Microsoft's WebView2 engine +/// with the Krypton Toolkit's theming system. It provides a consistent look and feel with other +/// Krypton controls while offering modern web rendering capabilities. +/// +/// +/// +/// Key Features: +/// - Modern web engine based on Microsoft Edge Chromium +/// - Full integration with Krypton theming system +/// - KryptonContextMenu support for custom right-click menus +/// - Designer support for Visual Studio +/// - Async navigation and JavaScript execution capabilities +/// - Customizable zoom levels and background colors +/// +/// +/// +/// Usage Example: +/// +/// var webView = new KryptonWebView2(); +/// webView.KryptonContextMenu = myKryptonContextMenu; +/// +/// // Initialize and navigate +/// await webView.EnsureCoreWebView2Async(); +/// webView.CoreWebView2?.Navigate("https://example.com"); +/// +/// +/// +/// +/// Requirements: +/// - WebView2 Runtime must be installed on the target system +/// - Compatible with .NET Framework 4.7.2+ and .NET 8+ +/// - Windows platform only +/// +/// +/// +/// See also: for legacy WebBrowser control with Krypton theming. +/// +/// +[ToolboxItem(true)] +[ToolboxBitmap(typeof(KryptonWebView2), "ToolboxBitmaps.WebView2.bmp")] +[Designer(typeof(KryptonWebView2Designer))] +[DesignerCategory(@"code")] +[Description(@"Enables the user to browse web pages using the modern WebView2 engine with Krypton theming support.")] +[CLSCompliant(false)] +public class KryptonWebView2 : WebView2 +{ + #region Instance Fields + + private PaletteBase _palette; + private readonly PaletteMode _paletteMode = PaletteMode.Global; + private KryptonContextMenu? _kryptonContextMenu; + private IRenderer _renderer; + + #endregion + + #region Identity + + /// + /// Initialize a new instance of the KryptonWebView2 class. + /// + /// + /// + /// The constructor initializes the control with Krypton-specific styling and behavior: + /// + /// + /// Enables double buffering for smooth rendering + /// Sets up resize redraw for proper repainting + /// Initializes the Krypton palette system + /// Registers for global palette change notifications + /// + /// + /// Note: The WebView2 engine itself is not initialized until EnsureCoreWebView2Async() + /// is called. This allows for better error handling and async initialization. + /// + /// + /// + /// + /// var webView = new KryptonWebView2(); + /// webView.Size = new Size(800, 600); + /// + /// // Initialize the WebView2 engine asynchronously + /// await webView.EnsureCoreWebView2Async(); + /// + /// + public KryptonWebView2() + { + // We use double buffering to reduce drawing flicker + SetStyle(ControlStyles.OptimizedDoubleBuffer | + ControlStyles.AllPaintingInWmPaint | + ControlStyles.UserPaint, true); + + // We need to repaint entire control whenever resized + SetStyle(ControlStyles.ResizeRedraw, true); + + // Yes, we want to be drawn double buffered by default + DoubleBuffered = true; + + SetPalette(KryptonManager.CurrentGlobalPalette); + + // Hook into global palette changes + KryptonManager.GlobalPaletteChanged += OnGlobalPaletteChanged; + } + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + /// + /// + /// This method performs the following cleanup operations: + /// + /// + /// Unhooks from global palette change notifications + /// Disposes of the associated KryptonContextMenu if present + /// Calls the base class Dispose method to clean up WebView2 resources + /// + /// + /// The WebView2 engine will automatically clean up its native resources when the control is disposed. + /// + /// + protected override void Dispose(bool disposing) + { + if (disposing) + { + // Unhook from global palette changes + KryptonManager.GlobalPaletteChanged -= OnGlobalPaletteChanged; + + // Dispose of the krypton context menu + _kryptonContextMenu?.Dispose(); + } + + base.Dispose(disposing); + } + + #endregion + + #region Public + + /// + /// Gets and sets the KryptonContextMenu to show when right-clicked. + /// + /// + /// A instance that will be displayed when the user right-clicks + /// on the web content, or null if no custom context menu should be shown. + /// + /// + /// + /// When set to a non-null value, this property overrides the default WebView2 context menu + /// with a Krypton-styled context menu. This allows for consistent theming across your + /// application while providing custom functionality. + /// + /// + /// The context menu will be shown at the mouse position when right-clicking within the + /// WebView2 control's client area. If the menu is activated via keyboard (Menu key), + /// it will be centered on the control. + /// + /// + /// Setting this property to null will restore the default WebView2 context menu behavior. + /// + /// + /// + /// + /// var contextMenu = new KryptonContextMenu(); + /// contextMenu.Items.Add(new KryptonContextMenuItem("Copy")); + /// contextMenu.Items.Add(new KryptonContextMenuItem("Paste")); + /// + /// webView.KryptonContextMenu = contextMenu; + /// + /// + [Category(@"Behavior")] + [Description(@"The shortcut menu to show when the user right-clicks the page.")] + [DefaultValue(null)] + public KryptonContextMenu? KryptonContextMenu + { + get => _kryptonContextMenu; + + set + { + if (_kryptonContextMenu != value) + { + if (_kryptonContextMenu != null) + { + _kryptonContextMenu.Disposed -= OnKryptonContextMenuDisposed; + } + + _kryptonContextMenu = value; + + if (_kryptonContextMenu != null) + { + _kryptonContextMenu.Disposed += OnKryptonContextMenuDisposed; + } + } + } + } + + #endregion + + #region Protected Overrides + + /// + /// Process Windows-based messages. + /// + /// A Windows-based message. + /// + /// + /// This method overrides the base WndProc to intercept context menu messages and provide + /// custom KryptonContextMenu handling. It processes the following message types: + /// + /// + /// WM_CONTEXTMENU - Context menu activation (right-click or Menu key) + /// WM_PARENTNOTIFY with WM_RBUTTONDOWN - Right mouse button down + /// + /// + /// When a KryptonContextMenu is assigned, this method will: + /// + /// + /// Extract the mouse position from the message parameters + /// Handle keyboard activation by centering the menu on the control + /// Adjust the position to match standard context menu behavior + /// Show the KryptonContextMenu if the mouse is within the client area + /// Consume the message to prevent default WebView2 context menu + /// + /// + /// If no KryptonContextMenu is assigned, the message is passed to the base class for + /// default WebView2 context menu handling. + /// + /// + protected override void WndProc(ref Message m) + { + if ((m.Msg == PI.WM_.CONTEXTMENU) || + (m.Msg == PI.WM_.PARENTNOTIFY && PI.LOWORD(m.WParam) == PI.WM_.RBUTTONDOWN)) + { + // Only interested in overriding the behavior when we have a krypton context menu + if (KryptonContextMenu != null) + { + // Extract the screen mouse position (if might not actually be provided) + var mousePt = new Point(PI.LOWORD(m.LParam), PI.HIWORD(m.LParam)); + + // If keyboard activated, the menu position is centered + if (((int)(long)m.LParam) == -1) + { + mousePt = new Point(Width / 2, Height / 2); + } + else + { + if (m.Msg == PI.WM_.CONTEXTMENU) + { + mousePt = PointToClient(mousePt); + } + + // Mouse point up and left 1 pixel so that the mouse overlaps the top left corner + // of the showing context menu just like it happens for a ContextMenuStrip. + mousePt.X -= 1; + mousePt.Y -= 1; + } + + // If the mouse position is within our client area + if (ClientRectangle.Contains(mousePt)) + { + // Show the context menu + KryptonContextMenu.Show(this, PointToScreen(mousePt)); + + // We eat the message! + return; + } + } + } + + base.WndProc(ref m); + } + + private void OnKryptonContextMenuDisposed(object? sender, EventArgs e) => + // When the current krypton context menu is disposed, we should remove + // it to prevent it being used again, as that would just throw an exception + // because it has been disposed. + KryptonContextMenu = null; + + #endregion + + #region Palette Controls + + /// Sets the palette being used. + /// The chosen palette. + private void SetPalette(PaletteBase palette) + { + if (palette != _palette) + { + // Unhook from current palette events + if (_palette != null) + { + _palette.BasePaletteChanged -= OnBaseChanged; + _palette.BaseRendererChanged -= OnBaseChanged; + } + + // Remember the new palette + _palette = palette; + + // Get the renderer associated with the palette + _renderer = _palette.GetRenderer(); + + // Hook to new palette events + if (_palette != null) + { + _palette.BasePaletteChanged += OnBaseChanged; + _palette.BaseRendererChanged += OnBaseChanged; + } + } + } + + /// Called when there is a change in base renderer or base palette. + /// The sender. + /// The instance containing the event data. + private void OnBaseChanged(object? sender, EventArgs e) => + // Change in base renderer or base palette require we fetch the latest renderer + _renderer = _palette.GetRenderer(); + + /// + /// Occurs when the global palette has been changed. + /// + /// Source of the event. + /// An EventArgs that contains the event data. + protected virtual void OnGlobalPaletteChanged(object? sender, EventArgs e) + { + // We only care if we are using the global palette + if (_paletteMode == PaletteMode.Global) + { + // Update self with the new global palette + SetPalette(KryptonManager.CurrentGlobalPalette); + } + } + + /// + /// Create a tool strip renderer appropriate for the current renderer/palette pair. + /// + /// + /// A instance that provides Krypton-themed rendering + /// for tool strips, or null if no renderer is available. + /// + /// + /// + /// This method creates a tool strip renderer that matches the current Krypton theme + /// and palette. The renderer is used internally by the control to ensure consistent + /// theming across all UI elements. + /// + /// + /// The method uses the resolved palette (either the control's specific palette or + /// the global palette) to create the appropriate renderer for the current theme. + /// + /// + /// This method is primarily used internally by the Krypton framework but can be + /// called by advanced users who need custom tool strip rendering. + /// + /// + /// + /// + /// var renderer = webView.CreateToolStripRenderer(); + /// if (renderer != null) + /// { + /// myToolStrip.Renderer = renderer; + /// } + /// + /// + [Browsable(false)] + [EditorBrowsable(EditorBrowsableState.Advanced)] + public ToolStripRenderer? CreateToolStripRenderer() + { + var palette = GetResolvedPalette() ?? KryptonManager.CurrentGlobalPalette; + return _renderer?.RenderToolStrip(palette); + } + + /// + /// Gets the resolved palette to actually use when drawing. + /// + /// + /// A instance that represents the currently active palette + /// for this control. + /// + /// + /// + /// This method returns the palette that is currently being used for rendering this control. + /// The resolved palette is determined by the control's palette mode and the global palette + /// settings. + /// + /// + /// This method is primarily used internally by the Krypton framework for rendering + /// operations and theme consistency. + /// + /// + [Browsable(false)] + [EditorBrowsable(EditorBrowsableState.Never)] + public PaletteBase GetResolvedPalette() => _palette; + + #endregion +} +#endif diff --git a/Source/Krypton Components/Krypton.Toolkit/Designers/Designers/KryptonWebView2Designer.cs b/Source/Krypton Components/Krypton.Toolkit/Designers/Designers/KryptonWebView2Designer.cs new file mode 100644 index 000000000..aa0a4ce6b --- /dev/null +++ b/Source/Krypton Components/Krypton.Toolkit/Designers/Designers/KryptonWebView2Designer.cs @@ -0,0 +1,38 @@ +#region BSD License +/* + * + * Original BSD 3-Clause License (https://github.com/ComponentFactory/Krypton/blob/master/LICENSE) + * © Component Factory Pty Ltd, 2006 - 2016, (Version 4.5.0.0) All rights reserved. + * + * New BSD 3-Clause License (https://github.com/Krypton-Suite/Standard-Toolkit/blob/master/LICENSE) + * Modifications by Peter Wagner (aka Wagnerp), Simon Coghlan (aka Smurf-IV), Giduac & Ahmed Abdelhameed et al. 2025 - 2025. All rights reserved. + * + */ +#endregion + +namespace Krypton.Toolkit; + +#if WEBVIEW2_AVAILABLE +internal class KryptonWebView2Designer : ControlDesigner +{ + #region Public Overrides + /// + /// Initializes the designer with the specified component. + /// + /// The IComponent to associate the designer with. + public override void Initialize([DisallowNull] IComponent component) + { + // Let base class do standard stuff + base.Initialize(component); + + Debug.Assert(component != null); + + // The resizing handles around the control need to change depending on the + // value of the AutoSize and AutoSizeMode properties. When in AutoSize you + // do not get the resizing handles, otherwise you do. + AutoResizeHandles = true; + } + + #endregion Public Overrides +} +#endif diff --git a/Source/Krypton Components/Krypton.Toolkit/Krypton.Toolkit 2022.csproj b/Source/Krypton Components/Krypton.Toolkit/Krypton.Toolkit 2022.csproj index 75d4087ba..7de85f834 100644 --- a/Source/Krypton Components/Krypton.Toolkit/Krypton.Toolkit 2022.csproj +++ b/Source/Krypton Components/Krypton.Toolkit/Krypton.Toolkit 2022.csproj @@ -57,6 +57,35 @@ + + + + ..\..\..\WebView2SDK\Microsoft.Web.WebView2.Core.dll + True + + + ..\..\..\WebView2SDK\Microsoft.Web.WebView2.WinForms.dll + True + + + + + + + ..\..\..\WebView2SDK\Microsoft.Web.WebView2.Core.dll + True + + + ..\..\..\WebView2SDK\Microsoft.Web.WebView2.WinForms.dll + True + + + + + + $(DefineConstants);WEBVIEW2_AVAILABLE + + Krypton.Toolkit @@ -535,6 +564,7 @@ + diff --git a/Source/Krypton Components/Krypton.Toolkit/ToolboxBitmaps/WebView2.bmp b/Source/Krypton Components/Krypton.Toolkit/ToolboxBitmaps/WebView2.bmp new file mode 100644 index 000000000..0b1f72a64 Binary files /dev/null and b/Source/Krypton Components/Krypton.Toolkit/ToolboxBitmaps/WebView2.bmp differ diff --git a/Source/Krypton Components/Krypton.Toolkit/Utilities/GraphicsExtensions.cs b/Source/Krypton Components/Krypton.Toolkit/Utilities/GraphicsExtensions.cs index 93ee8db18..32cbbe788 100644 --- a/Source/Krypton Components/Krypton.Toolkit/Utilities/GraphicsExtensions.cs +++ b/Source/Krypton Components/Krypton.Toolkit/Utilities/GraphicsExtensions.cs @@ -22,6 +22,7 @@ public static class GraphicsExtensions public static Icon? LoadIcon(IconType type, Size size) { var hIcon = ImageNativeMethods.LoadImage(IntPtr.Zero, $"#{(int)type}", 1, size.Width, size.Height, 0); + return hIcon == IntPtr.Zero ? null : Icon.FromHandle(hIcon); } @@ -35,7 +36,9 @@ public static class GraphicsExtensions try { if (executablePath != null) - { result = Icon.ExtractAssociatedIcon(executablePath); } + { + result = Icon.ExtractAssociatedIcon(executablePath); + } } catch (Exception e) { @@ -136,6 +139,7 @@ public static Icon LoadIcon(IconType type, Size size) { throw new ArgumentNullException(nameof(filePath)); } + var hIconEx = new IntPtr[] { IntPtr.Zero }; try { @@ -192,7 +196,8 @@ public static Size GetScreenSize() => /// The custom image. /// The image, based on the type chosen. /// iconType - null - public static Image? GetKryptonMessageBoxImageType(KryptonMessageBoxIcon iconType, Size? imageSize, Image? customImage = null) + public static Image? GetKryptonMessageBoxImageType(KryptonMessageBoxIcon iconType, Size? imageSize, + Image? customImage = null) { var newSize = imageSize ?? new Size(32, 32); @@ -224,18 +229,10 @@ public static Size GetScreenSize() => case KryptonMessageBoxIcon.Information: return MessageBoxImageResources.GenericInformation; case KryptonMessageBoxIcon.Shield: - if (OSUtilities.IsAtLeastWindowsEleven) - { - return UACShieldIconResources.UACShieldWindows11; - } - else if (OSUtilities.IsWindowsTen) - { - return UACShieldIconResources.UACShieldWindows10; - } - else - { - return UACShieldIconResources.UACShieldWindows7881; - } + { + var messageBoxShieldIcon = ExtractIconFromImageresInternal(ImageresIconID.Shield); + return messageBoxShieldIcon?.ToBitmap(); + } case KryptonMessageBoxIcon.WindowsLogo: if (OSUtilities.IsAtLeastWindowsEleven) { @@ -297,22 +294,10 @@ public static Size GetScreenSize() => case KryptonToastNotificationIcon.Information: return ToastNotificationImageResources.Toast_Notification_Information_128_x_128; case KryptonToastNotificationIcon.Shield: - if (OSUtilities.IsAtLeastWindowsEleven) - { - return ToastNotificationImageResources.Toast_Notification_UAC_Shield_Windows_11_128_x_128; - } - else if (OSUtilities.IsWindowsTen) - { - return ToastNotificationImageResources.Toast_Notification_UAC_Shield_Windows_10_128_x_128; - } - else if (OSUtilities.IsWindowsEightPointOne || OSUtilities.IsWindowsEight || OSUtilities.IsWindowsSeven) - { - return ToastNotificationImageResources.Toast_Notification_UAC_Shield_Windows_7_and_8_128_x_128; - } - else - { - return ScaleImage(SystemIcons.Shield.ToBitmap(), newSize); - } + { + var messageBoxShieldIcon = ExtractIconFromImageresInternal(ImageresIconID.Shield, IconSize.Huge); + return messageBoxShieldIcon?.ToBitmap(); + } case KryptonToastNotificationIcon.WindowsLogo: if (OSUtilities.IsAtLeastWindowsEleven) { @@ -328,7 +313,8 @@ public static Size GetScreenSize() => } case KryptonToastNotificationIcon.Application: return customImage != null - ? ScaleImage(customImage, newSize) : ScaleImage(SystemIcons.Application.ToBitmap(), newSize); + ? ScaleImage(customImage, newSize) + : ScaleImage(SystemIcons.Application.ToBitmap(), newSize); case KryptonToastNotificationIcon.SystemApplication: return ScaleImage(SystemIcons.Application.ToBitmap(), newSize); case KryptonToastNotificationIcon.Ok: @@ -374,5 +360,332 @@ public static Size GetScreenSize() => return resolved as Bitmap ?? new Bitmap(resolved); } -} -#endregion \ No newline at end of file + + /// Extracts an icon from imageres.dll using the specified icon ID and size. + /// The icon ID from ImageresIconID enum. + /// The size of the icon to extract. Defaults to Medium (32x32). + /// The strategy for selecting fallback icons. Defaults to OS-based selection. + /// The extracted icon, or null if extraction fails. + public static Icon? ExtractIconFromImageres(int iconId, IconSize iconSize = IconSize.Medium, IconSelectionStrategy selectionStrategy = IconSelectionStrategy.OSBased) => ExtractIconFromImageresInternal((ImageresIconID)iconId, iconSize, selectionStrategy); + + /// Extracts an icon from imageres.dll using the specified icon ID and size. + /// The icon ID from ImageresIconID enum. + /// The size of the icon to extract. Defaults to Medium (32x32). + /// The strategy for selecting fallback icons. Defaults to OS-based selection. + /// The extracted icon, or null if extraction fails. + internal static Icon? ExtractIconFromImageresInternal(ImageresIconID iconId, IconSize iconSize = IconSize.Medium, IconSelectionStrategy selectionStrategy = IconSelectionStrategy.OSBased) + { + var size = GetSizeFromIconSize(iconSize); + var isLargeIcon = size.Width > 32; // Use large icon extraction for sizes larger than 32x32 + + // Try to extract from imageres.dll first + var icon = ExtractIcon(Libraries.Imageres, (int)iconId, isLargeIcon); + if (icon != null) + { + return icon; + } + + // Fallback to embedded resources for specific icons + return GetFallbackIconFromResources(iconId, size, selectionStrategy); + } + + /// Gets the pixel size corresponding to an IconSize enum value. + /// The IconSize enum value. + /// The corresponding pixel size. + private static Size GetSizeFromIconSize(IconSize iconSize) => new((int)iconSize, (int)iconSize); + + /// Gets a fallback icon from embedded resources when imageres.dll is not available. + /// The icon ID that was requested. + /// The target size for the icon. + /// The strategy for selecting fallback icons. + /// The fallback icon, or null if no suitable fallback is available. + private static Icon? GetFallbackIconFromResources(ImageresIconID iconId, Size targetSize, IconSelectionStrategy selectionStrategy) + { + try + { + // Only provide fallbacks for specific icons that we have embedded resources for + switch (iconId) + { + case ImageresIconID.Shield: + case ImageresIconID.ShieldAlt: + return GetUACShieldFallbackIcon(targetSize, selectionStrategy); + default: + // For other icons, we don't have embedded fallbacks + return null; + } + } + catch (Exception) + { + // If fallback fails, return null + return null; + } + } + + /// Gets a UAC shield icon from embedded resources based on the current OS or theme. + /// The target size for the icon. + /// The strategy for selecting the icon. + /// The UAC shield icon, or null if extraction fails. + private static Icon? GetUACShieldFallbackIcon(Size targetSize, IconSelectionStrategy selectionStrategy) + { + try + { + Image? shieldImage; + + if (selectionStrategy == IconSelectionStrategy.ThemeBased) + { + // Use theme-based selection + shieldImage = GetThemeBasedShieldImage(targetSize); + } + else + { + // Use OS-based selection (default behavior) + shieldImage = GetOSBasedShieldImage(targetSize); + } + + if (shieldImage != null) + { + // Convert to icon + using var bitmap = new Bitmap(shieldImage); + var iconHandle = bitmap.GetHicon(); + return Icon.FromHandle(iconHandle); + } + + return null; + } + catch (Exception) + { + return null; + } + } + + /// Gets a Windows 11 UAC shield image at the specified size. + /// The target size. + /// The shield image, or null if not available. + private static Image? GetWindows11ShieldImage(Size targetSize) + { + return targetSize.Width switch + { + 8 => Windows11UACShieldImageResources.Windows_11_UAC_Shield_16_x_16, // Use 16x16 for 8x8 + 16 => Windows11UACShieldImageResources.Windows_11_UAC_Shield_16_x_16, + 20 => Windows11UACShieldImageResources.Windows_11_UAC_Shield_20_x_20, + 24 => Windows11UACShieldImageResources.Windows_11_UAC_Shield_24_x_24, + 32 => Windows11UACShieldImageResources.Windows_11_UAC_Shield_32_x_32, + 40 => Windows11UACShieldImageResources.Windows_11_UAC_Shield_40_x_40, + 48 => Windows11UACShieldImageResources.Windows_11_UAC_Shield_48_x_48, + 64 => Windows11UACShieldImageResources.Windows_11_UAC_Shield_64_x_64, + 96 => Windows11UACShieldImageResources.Windows_11_UAC_Shield_64_x_64, // Use 64x64 for 96x96 + 128 => Windows11UACShieldImageResources.Windows_11_UAC_Shield_64_x_64, // Use 64x64 for 128x128 + 192 => Windows11UACShieldImageResources.Windows_11_UAC_Shield_256_x_256, // Use 256x256 for 192x192 + 256 => Windows11UACShieldImageResources.Windows_11_UAC_Shield_256_x_256, + _ => Windows11UACShieldImageResources.Windows_11_UAC_Shield_32_x_32 // Default to 32x32 + }; + } + + /// Gets a Windows 10 UAC shield image at the specified size. + /// The target size. + /// The shield image, or null if not available. + private static Image? GetWindows10ShieldImage(Size targetSize) + { + return targetSize.Width switch + { + 8 => Windows10UACShieldImageResources.Windows_10_UAC_Shield_16_x_16, // Use 16x16 for 8x8 + 16 => Windows10UACShieldImageResources.Windows_10_UAC_Shield_16_x_16, + 20 => Windows10UACShieldImageResources.Windows_10_UAC_Shield_20_x_20, + 24 => Windows10UACShieldImageResources.Windows_10_UAC_Shield_24_x_24, + 32 => Windows10UACShieldImageResources.Windows_10_UAC_Shield_32_x_32, + 40 => Windows10UACShieldImageResources.Windows_10_UAC_Shield_40_x_40, + 48 => Windows10UACShieldImageResources.Windows_10_UAC_Shield_48_x_48, + 64 => Windows10UACShieldImageResources.Windows_10_UAC_Shield_64_x_64, + 96 => Windows10UACShieldImageResources.Windows_10_UAC_Shield_64_x_64, // Use 64x64 for 96x96 + 128 => Windows10UACShieldImageResources.Windows_10_UAC_Shield_64_x_64, // Use 64x64 for 128x128 + 192 => Windows10UACShieldImageResources.Windows_10_UAC_Shield_256_x_256, // Use 256x256 for 192x192 + 256 => Windows10UACShieldImageResources.Windows_10_UAC_Shield_256_x_256, + _ => Windows10UACShieldImageResources.Windows_10_UAC_Shield_32_x_32 // Default to 32x32 + }; + } + + /// Gets a Windows 7/8.x UAC shield image at the specified size. + /// The target size. + /// The shield image, or null if not available. + private static Image? GetWindows7And8xShieldImage(Size targetSize) + { + return targetSize.Width switch + { + 8 => Windows7And8xUACShieldImageResources.Windows_7_and_8x_UAC_Shield_8_x_8, + 16 => Windows7And8xUACShieldImageResources.Windows_7_and_8x_UAC_Shield_16_x_16, + 24 => Windows7And8xUACShieldImageResources.Windows_7_and_8x_UAC_Shield_24_x_24, + 32 => Windows7And8xUACShieldImageResources.Windows_7_and_8x_UAC_Shield_32_x_32, + 48 => Windows7And8xUACShieldImageResources.Windows_7_and_8x_UAC_Shield_48_x_48, + 64 => Windows7And8xUACShieldImageResources.Windows_7_and_8x_UAC_Shield_64_x_64, + 96 => Windows7And8xUACShieldImageResources.Windows_7_and_8x_UAC_Shield_64_x_64, // Use 64x64 for 96x96 + 128 => Windows7And8xUACShieldImageResources.Windows_7_and_8x_UAC_Shield_128_x_128, + 192 => Windows7And8xUACShieldImageResources.Windows_7_and_8x_UAC_Shield_256_x_256, // Use 256x256 for 192x192 + 256 => Windows7And8xUACShieldImageResources.Windows_7_and_8x_UAC_Shield_256_x_256, + _ => Windows7And8xUACShieldImageResources.Windows_7_and_8x_UAC_Shield_32_x_32 // Default to 32x32 + }; + } + + /// Gets a UAC shield image based on the current Krypton theme. + /// The target size. + /// The shield image, or null if not available. + private static Image? GetThemeBasedShieldImage(Size targetSize) + { + var currentTheme = KryptonManager.CurrentGlobalPaletteMode; + + // Map themes to appropriate Windows versions + if (IsVistaCompatibleTheme(currentTheme)) + { + return GetWindowsVistaShieldImage(targetSize); + } + else if (IsWindows7CompatibleTheme(currentTheme)) + { + return GetWindows7And8xShieldImage(targetSize); + } + else if (IsWindows10CompatibleTheme(currentTheme)) + { + // Prefer Windows 11 icons for modern themes, fallback to Windows 10 + if (OSUtilities.IsAtLeastWindowsEleven) + { + return GetWindows11ShieldImage(targetSize); + } + else + { + return GetWindows10ShieldImage(targetSize); + } + } + else + { + // Default to OS-based selection for unknown themes + return GetOSBasedShieldImage(targetSize); + } + } + + /// Gets a UAC shield image based on the current OS. + /// The target size. + /// The shield image, or null if not available. + private static Image? GetOSBasedShieldImage(Size targetSize) + { + // Get the appropriate shield image based on OS + if (OSUtilities.IsAtLeastWindowsEleven) + { + return GetWindows11ShieldImage(targetSize); + } + else if (OSUtilities.IsWindowsTen) + { + return GetWindows10ShieldImage(targetSize); + } + else if (OSUtilities.IsWindowsEightPointOne || OSUtilities.IsWindowsEight || OSUtilities.IsWindowsSeven) + { + return GetWindows7And8xShieldImage(targetSize); + } + else + { + return GetWindowsVistaShieldImage(targetSize); + } + } + + /// Determines if a theme is compatible with Windows Vista icon style. + /// The theme to check. + /// True if the theme should use Windows Vista icons. + private static bool IsVistaCompatibleTheme(PaletteMode theme) + { + return theme switch + { + PaletteMode.ProfessionalSystem => true, + PaletteMode.ProfessionalOffice2003 => true, + PaletteMode.Office2007Blue => true, + PaletteMode.Office2007BlueDarkMode => true, + PaletteMode.Office2007BlueLightMode => true, + PaletteMode.Office2007Silver => true, + PaletteMode.Office2007SilverDarkMode => true, + PaletteMode.Office2007SilverLightMode => true, + PaletteMode.Office2007White => true, + PaletteMode.Office2007Black => true, + PaletteMode.Office2007BlackDarkMode => true, + PaletteMode.SparkleBlue => true, + PaletteMode.SparkleBlueDarkMode => true, + PaletteMode.SparkleBlueLightMode => true, + PaletteMode.SparkleOrange => true, + PaletteMode.SparkleOrangeDarkMode => true, + PaletteMode.SparkleOrangeLightMode => true, + PaletteMode.SparklePurple => true, + PaletteMode.SparklePurpleDarkMode => true, + PaletteMode.SparklePurpleLightMode => true, + _ => false + }; + } + + /// Determines if a theme is compatible with Windows 7/8.x icon style. + /// The theme to check. + /// True if the theme should use Windows 7/8.x icons. + private static bool IsWindows7CompatibleTheme(PaletteMode theme) + { + return theme switch + { + PaletteMode.Office2010Blue => true, + PaletteMode.Office2010BlueDarkMode => true, + PaletteMode.Office2010BlueLightMode => true, + PaletteMode.Office2010Silver => true, + PaletteMode.Office2010SilverDarkMode => true, + PaletteMode.Office2010SilverLightMode => true, + PaletteMode.Office2010White => true, + PaletteMode.Office2010Black => true, + PaletteMode.Office2010BlackDarkMode => true, + PaletteMode.Office2013White => true, + PaletteMode.VisualStudio2010Render2007 => true, + PaletteMode.VisualStudio2010Render2010 => true, + PaletteMode.VisualStudio2010Render2013 => true, + PaletteMode.VisualStudio2010Render365 => true, + _ => false + }; + } + + /// Determines if a theme is compatible with Windows 10/11 icon style. + /// The theme to check. + /// True if the theme should use Windows 10/11 icons. + private static bool IsWindows10CompatibleTheme(PaletteMode theme) + { + return theme switch + { + PaletteMode.Microsoft365Blue => true, + PaletteMode.Microsoft365BlueDarkMode => true, + PaletteMode.Microsoft365BlueLightMode => true, + PaletteMode.Microsoft365Silver => true, + PaletteMode.Microsoft365SilverDarkMode => true, + PaletteMode.Microsoft365SilverLightMode => true, + PaletteMode.Microsoft365White => true, + PaletteMode.Microsoft365Black => true, + PaletteMode.Microsoft365BlackDarkMode => true, + PaletteMode.Microsoft365BlackDarkModeAlternate => true, + PaletteMode.MaterialLight => true, + PaletteMode.MaterialDark => true, + PaletteMode.MaterialLightRipple => true, + PaletteMode.MaterialDarkRipple => true, + _ => false + }; + } + + /// Gets a Windows Vista UAC shield image at the specified size. + /// The target size. + /// The shield image, or null if not available. + private static Image? GetWindowsVistaShieldImage(Size targetSize) + { + return targetSize.Width switch + { + 8 => WindowsVistaUACShieldImageResources.Windows_Vista_UAC_Shield_8_x_8, + 16 => WindowsVistaUACShieldImageResources.Windows_Vista_UAC_Shield_16_x_16, + 24 => WindowsVistaUACShieldImageResources.Windows_Vista_UAC_Shield_24_x_24, + 32 => WindowsVistaUACShieldImageResources.Windows_Vista_UAC_Shield_32_x_32, + 48 => WindowsVistaUACShieldImageResources.Windows_Vista_UAC_Shield_48_x_48, + 64 => WindowsVistaUACShieldImageResources.Windows_Vista_UAC_Shield_32_x_32, // Use 32x32 for 64x64 + 96 => WindowsVistaUACShieldImageResources.Windows_Vista_UAC_Shield_128_x_128, // Use 128x128 for 96x96 + 128 => WindowsVistaUACShieldImageResources.Windows_Vista_UAC_Shield_128_x_128, + 192 => WindowsVistaUACShieldImageResources.Windows_Vista_UAC_Shield_256_x_256, // Use 256x256 for 192x192 + 256 => WindowsVistaUACShieldImageResources.Windows_Vista_UAC_Shield_256_x_256, + _ => WindowsVistaUACShieldImageResources.Windows_Vista_UAC_Shield_32_x_32 // Default to 32x32 + }; + } + + + #endregion +} \ No newline at end of file diff --git a/Source/Krypton Components/TestForm/KryptonWebView2Test.Designer.cs b/Source/Krypton Components/TestForm/KryptonWebView2Test.Designer.cs new file mode 100644 index 000000000..cb72643f4 --- /dev/null +++ b/Source/Krypton Components/TestForm/KryptonWebView2Test.Designer.cs @@ -0,0 +1,196 @@ +#region BSD License +/* + * + * Original BSD 3-Clause License (https://github.com/ComponentFactory/Krypton/blob/master/LICENSE) + * © Component Factory Pty Ltd, 2006 - 2016, (Version 4.5.0.0) All rights reserved. + * + * New BSD 3-Clause License (https://github.com/Krypton-Suite/Standard-Toolkit/blob/master/LICENSE) + * Modifications by Peter Wagner (aka Wagnerp), Simon Coghlan (aka Smurf-IV), Giduac & Ahmed Abdelhameed, tobitege et al. 2025 - 2025. All rights reserved. + * + */ +#endregion + +namespace TestForm +{ + partial class KryptonWebView2Test + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + this.kryptonPanel1 = new Krypton.Toolkit.KryptonPanel(); + this.kryptonWebView21 = new Krypton.Toolkit.KryptonWebView2(); + this.kryptonLabel1 = new Krypton.Toolkit.KryptonLabel(); + this.kryptonPanel2 = new Krypton.Toolkit.KryptonPanel(); + this.kbtnRefresh = new Krypton.Toolkit.KryptonButton(); + this.kbtnForward = new Krypton.Toolkit.KryptonButton(); + this.kbtnBack = new Krypton.Toolkit.KryptonButton(); + this.kbtnNavigate = new Krypton.Toolkit.KryptonButton(); + this.kryptonTextBox1 = new Krypton.Toolkit.KryptonTextBox(); + this.kryptonLabel2 = new Krypton.Toolkit.KryptonLabel(); + ((System.ComponentModel.ISupportInitialize)(this.kryptonPanel1)).BeginInit(); + this.kryptonPanel1.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.kryptonPanel2)).BeginInit(); + this.kryptonPanel2.SuspendLayout(); + this.SuspendLayout(); + // + // kryptonPanel1 + // + this.kryptonPanel1.Controls.Add(this.kryptonWebView21); + this.kryptonPanel1.Controls.Add(this.kryptonLabel1); + this.kryptonPanel1.Controls.Add(this.kryptonPanel2); + this.kryptonPanel1.Dock = System.Windows.Forms.DockStyle.Fill; + this.kryptonPanel1.Location = new System.Drawing.Point(0, 0); + this.kryptonPanel1.Name = "kryptonPanel1"; + this.kryptonPanel1.PanelBackStyle = Krypton.Toolkit.PaletteBackStyle.ControlClient; + this.kryptonPanel1.Size = new System.Drawing.Size(1000, 700); + this.kryptonPanel1.TabIndex = 0; + // + // kryptonWebView21 + // + this.kryptonWebView21.AllowExternalDrop = true; + this.kryptonWebView21.CreationProperties = null; + this.kryptonWebView21.DefaultBackgroundColor = System.Drawing.Color.White; + this.kryptonWebView21.Dock = System.Windows.Forms.DockStyle.Fill; + this.kryptonWebView21.Location = new System.Drawing.Point(0, 60); + this.kryptonWebView21.Name = "kryptonWebView21"; + this.kryptonWebView21.Size = new System.Drawing.Size(1000, 640); + this.kryptonWebView21.TabIndex = 2; + this.kryptonWebView21.ZoomFactor = 1D; + this.kryptonWebView21.NavigationCompleted += new System.EventHandler(this.kryptonWebView21_NavigationCompleted); + // + // kryptonLabel1 + // + this.kryptonLabel1.Dock = System.Windows.Forms.DockStyle.Fill; + this.kryptonLabel1.LabelStyle = Krypton.Toolkit.LabelStyle.NormalControl; + this.kryptonLabel1.Location = new System.Drawing.Point(0, 60); + this.kryptonLabel1.Name = "kryptonLabel1"; + this.kryptonLabel1.Size = new System.Drawing.Size(1000, 640); + this.kryptonLabel1.TabIndex = 1; + this.kryptonLabel1.Text = "Initializing WebView2..."; + this.kryptonLabel1.Values.Text = "Initializing WebView2..."; + this.kryptonLabel1.Visible = false; + // + // kryptonPanel2 + // + this.kryptonPanel2.Controls.Add(this.kbtnRefresh); + this.kryptonPanel2.Controls.Add(this.kbtnForward); + this.kryptonPanel2.Controls.Add(this.kbtnBack); + this.kryptonPanel2.Controls.Add(this.kbtnNavigate); + this.kryptonPanel2.Controls.Add(this.kryptonTextBox1); + this.kryptonPanel2.Controls.Add(this.kryptonLabel2); + this.kryptonPanel2.Dock = System.Windows.Forms.DockStyle.Top; + this.kryptonPanel2.Location = new System.Drawing.Point(0, 0); + this.kryptonPanel2.Name = "kryptonPanel2"; + this.kryptonPanel2.PanelBackStyle = Krypton.Toolkit.PaletteBackStyle.ControlClient; + this.kryptonPanel2.Size = new System.Drawing.Size(1000, 60); + this.kryptonPanel2.TabIndex = 0; + // + // kbtnRefresh + // + this.kbtnRefresh.Location = new System.Drawing.Point(450, 30); + this.kbtnRefresh.Name = "kbtnRefresh"; + this.kbtnRefresh.Size = new System.Drawing.Size(75, 25); + this.kbtnRefresh.TabIndex = 5; + this.kbtnRefresh.Values.Text = "Refresh"; + this.kbtnRefresh.Click += new System.EventHandler(this.kbtnRefresh_Click); + // + // kbtnForward + // + this.kbtnForward.Location = new System.Drawing.Point(370, 30); + this.kbtnForward.Name = "kbtnForward"; + this.kbtnForward.Size = new System.Drawing.Size(75, 25); + this.kbtnForward.TabIndex = 4; + this.kbtnForward.Values.Text = "Forward"; + this.kbtnForward.Click += new System.EventHandler(this.kbtnForward_Click); + // + // kbtnBack + // + this.kbtnBack.Location = new System.Drawing.Point(290, 30); + this.kbtnBack.Name = "kbtnBack"; + this.kbtnBack.Size = new System.Drawing.Size(75, 25); + this.kbtnBack.TabIndex = 3; + this.kbtnBack.Values.Text = "Back"; + this.kbtnBack.Click += new System.EventHandler(this.kbtnBack_Click); + // + // kbtnNavigate + // + this.kbtnNavigate.Location = new System.Drawing.Point(530, 30); + this.kbtnNavigate.Name = "kbtnNavigate"; + this.kbtnNavigate.Size = new System.Drawing.Size(75, 25); + this.kbtnNavigate.TabIndex = 2; + this.kbtnNavigate.Values.Text = "Navigate"; + this.kbtnNavigate.Click += new System.EventHandler(this.kbtnNavigate_Click); + // + // kryptonTextBox1 + // + this.kryptonTextBox1.Location = new System.Drawing.Point(80, 32); + this.kryptonTextBox1.Name = "kryptonTextBox1"; + this.kryptonTextBox1.Size = new System.Drawing.Size(200, 23); + this.kryptonTextBox1.TabIndex = 1; + this.kryptonTextBox1.Text = "https://www.microsoft.com"; + // + // kryptonLabel2 + // + this.kryptonLabel2.Location = new System.Drawing.Point(10, 35); + this.kryptonLabel2.Name = "kryptonLabel2"; + this.kryptonLabel2.Size = new System.Drawing.Size(64, 20); + this.kryptonLabel2.TabIndex = 0; + this.kryptonLabel2.Values.Text = "Address:"; + // + // KryptonWebView2Test + // + this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(1000, 700); + this.Controls.Add(this.kryptonPanel1); + this.Name = "KryptonWebView2Test"; + this.Text = "KryptonWebView2 Test"; + this.WindowState = System.Windows.Forms.FormWindowState.Maximized; + ((System.ComponentModel.ISupportInitialize)(this.kryptonPanel1)).EndInit(); + this.kryptonPanel1.ResumeLayout(false); + this.kryptonPanel1.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)(this.kryptonPanel2)).EndInit(); + this.kryptonPanel2.ResumeLayout(false); + this.kryptonPanel2.PerformLayout(); + this.ResumeLayout(false); + + } + + #endregion + + private Krypton.Toolkit.KryptonPanel kryptonPanel1; + private Krypton.Toolkit.KryptonWebView2 kryptonWebView21; + private Krypton.Toolkit.KryptonLabel kryptonLabel1; + private Krypton.Toolkit.KryptonPanel kryptonPanel2; + private Krypton.Toolkit.KryptonButton kbtnRefresh; + private Krypton.Toolkit.KryptonButton kbtnForward; + private Krypton.Toolkit.KryptonButton kbtnBack; + private Krypton.Toolkit.KryptonButton kbtnNavigate; + private Krypton.Toolkit.KryptonTextBox kryptonTextBox1; + private Krypton.Toolkit.KryptonLabel kryptonLabel2; + } +} diff --git a/Source/Krypton Components/TestForm/KryptonWebView2Test.cs b/Source/Krypton Components/TestForm/KryptonWebView2Test.cs new file mode 100644 index 000000000..e762645f8 --- /dev/null +++ b/Source/Krypton Components/TestForm/KryptonWebView2Test.cs @@ -0,0 +1,180 @@ +#region BSD License +/* + * + * Original BSD 3-Clause License (https://github.com/ComponentFactory/Krypton/blob/master/LICENSE) + * © Component Factory Pty Ltd, 2006 - 2016, (Version 4.5.0.0) All rights reserved. + * + * New BSD 3-Clause License (https://github.com/Krypton-Suite/Standard-Toolkit/blob/master/LICENSE) + * Modifications by Peter Wagner (aka Wagnerp), Simon Coghlan (aka Smurf-IV), Giduac & Ahmed Abdelhameed, tobitege et al. 2025 - 2025. All rights reserved. + * + */ +#endregion + +using Microsoft.Web.WebView2.Core; + +namespace TestForm; + +/// +/// Test form demonstrating the KryptonWebView2 control functionality. +/// +/// +/// This form showcases the key features of the KryptonWebView2 control including: +/// - Control initialization and error handling +/// - Navigation with address bar +/// - Navigation controls (Back, Forward, Refresh) +/// - Integration with Krypton theming +/// - Proper async/await patterns for WebView2 operations +/// +/// +/// +/// The form includes a toolbar with navigation controls and an address bar, +/// while the main area displays the WebView2 control. Error handling is +/// demonstrated for WebView2 initialization failures. +/// +/// +public partial class KryptonWebView2Test : KryptonForm +{ + public KryptonWebView2Test() + { + InitializeComponent(); + InitializeWebView2(); + } + + /// + /// Initializes the WebView2 control asynchronously and navigates to a default page. + /// + /// + /// This method demonstrates proper WebView2 initialization with error handling. + /// If initialization fails, the WebView2 control is hidden and an error message + /// is displayed to the user with instructions to install the WebView2 Runtime. + /// + private async void InitializeWebView2() + { + try + { + // Initialize the WebView2 control + await kryptonWebView21.EnsureCoreWebView2Async(); + + // Navigate to a test page + kryptonWebView21.CoreWebView2?.Navigate("https://www.microsoft.com"); + } + catch (Exception ex) + { + // If WebView2 fails to initialize, show a message + kryptonWebView21.Visible = false; + kryptonLabel1.Text = $"WebView2 initialization failed: {ex.Message}\n\nPlease ensure WebView2 Runtime is installed."; + kryptonLabel1.Visible = true; + } + } + + /// + /// Handles the Navigate button click event. + /// + /// The button that raised the event. + /// Event arguments. + /// + /// This method demonstrates navigation with URL validation and protocol handling. + /// If the entered URL doesn't have a protocol, HTTPS is automatically added. + /// Navigation errors are caught and displayed to the user. + /// + private void kbtnNavigate_Click(object sender, EventArgs e) + { + try + { + var url = kryptonTextBox1.Text.Trim(); + if (!string.IsNullOrEmpty(url)) + { + // Add protocol if not present + if (!url.StartsWith("http://") && !url.StartsWith("https://")) + { + url = "https://" + url; + } + + kryptonWebView21.CoreWebView2?.Navigate(url); + } + } + catch (Exception ex) + { + MessageBox.Show($"Navigation error: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + } + } + + /// + /// Handles the Back button click event. + /// + /// The button that raised the event. + /// Event arguments. + /// + /// Demonstrates navigation history management by going back to the previous page. + /// + private void kbtnBack_Click(object sender, EventArgs e) + { + try + { + kryptonWebView21.CoreWebView2?.GoBack(); + } + catch (Exception ex) + { + MessageBox.Show($"Navigation error: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + } + } + + /// + /// Handles the Forward button click event. + /// + /// The button that raised the event. + /// Event arguments. + /// + /// Demonstrates navigation history management by going forward to the next page. + /// + private void kbtnForward_Click(object sender, EventArgs e) + { + try + { + kryptonWebView21.CoreWebView2?.GoForward(); + } + catch (Exception ex) + { + MessageBox.Show($"Navigation error: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + } + } + + /// + /// Handles the Refresh button click event. + /// + /// The button that raised the event. + /// Event arguments. + /// + /// Demonstrates page reload functionality by refreshing the current page. + /// + private void kbtnRefresh_Click(object sender, EventArgs e) + { + try + { + kryptonWebView21.CoreWebView2?.Reload(); + } + catch (Exception ex) + { + MessageBox.Show($"Navigation error: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + } + } + + /// + /// Handles the NavigationCompleted event from the WebView2 control. + /// + /// The WebView2 control that raised the event. + /// Navigation completion event arguments. + /// + /// This method demonstrates how to handle navigation completion events. + /// On successful navigation, the address bar is updated with the current URL. + /// This provides visual feedback to the user about the current page location. + /// + private void kryptonWebView21_NavigationCompleted(object sender, CoreWebView2NavigationCompletedEventArgs e) + { + // Update the address bar with the current URL + if (e.IsSuccess && kryptonWebView21.CoreWebView2 != null) + { + kryptonTextBox1.Text = kryptonWebView21.CoreWebView2.Source; + } + } +} diff --git a/Source/Krypton Components/TestForm/KryptonWebView2Test.resx b/Source/Krypton Components/TestForm/KryptonWebView2Test.resx new file mode 100644 index 000000000..4f03a7d1d --- /dev/null +++ b/Source/Krypton Components/TestForm/KryptonWebView2Test.resx @@ -0,0 +1,119 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 17, 17 + + diff --git a/Source/Krypton Components/TestForm/TestForm.csproj b/Source/Krypton Components/TestForm/TestForm.csproj index 694c1a7dd..f8fbcbe3f 100644 --- a/Source/Krypton Components/TestForm/TestForm.csproj +++ b/Source/Krypton Components/TestForm/TestForm.csproj @@ -24,6 +24,30 @@ + + + + ..\..\..\WebView2SDK\Microsoft.Web.WebView2.Core.dll + True + + + ..\..\..\WebView2SDK\Microsoft.Web.WebView2.WinForms.dll + True + + + + + + + ..\..\..\WebView2SDK\Microsoft.Web.WebView2.Core.dll + True + + + ..\..\..\WebView2SDK\Microsoft.Web.WebView2.WinForms.dll + True + + + True diff --git a/run.cmd b/run.cmd index cf31c1ee6..436ca62af 100644 --- a/run.cmd +++ b/run.cmd @@ -1,12 +1,10 @@ -:: Last updated: Wednesday 21st August, 2024 @ 19:00 - @echo off title Krypton Toolkit Build System cls -@echo Welcome to the Krypton Toolkit Build system, version: 2.4. Please select an option below. +@echo Welcome to the Krypton Toolkit Build system, version: 2.4a. Please select an option below. echo: @echo ============================================================================================== echo: @@ -16,17 +14,18 @@ echo 3. Create NuGet packages echo 4. Build and Pack Toolkit echo 5. Debug project echo 6. NuGet Tools -::echo 7. Miscellaneous tasks -echo 7. End +echo 7. WebView2 SDK Tools +echo 8. End echo: -set /p answer="Enter number (1 - 7): " +set /p answer="Enter number (1 - 8): " if %answer%==1 (goto cleanproject) if %answer%==2 (goto buildproject) if %answer%==3 (goto createnugetpackages) if %answer%==4 (goto buildandpacktoolkit) if %answer%==5 (goto debugproject) if %answer%==6 (goto nugettools) -if %answer%==7 (goto exitbuildsystem) +if %answer%==7 (goto webview2tools) +if %answer%==8 (goto exitbuildsystem) @echo Invalid input, please try again. @@ -46,8 +45,8 @@ echo 3. Create NuGet packages echo 4. Build and Pack Toolkit echo 5. Debug project echo 6. NuGet Tools -::echo 7. Miscellaneous tasks -echo 7. End +echo 7. WebView2 SDK Tools +echo 8. End echo: set /p answer="Enter number (1 - 8): " if %answer%==1 (goto cleanproject) @@ -56,8 +55,8 @@ if %answer%==3 (goto createnugetpackages) if %answer%==4 (goto buildandpacktoolkit) if %answer%==5 (goto debugproject) if %answer%==6 (goto nugettools) -::if %answer%==7 (goto miscellaneoustasks) -if %answer%==7 (goto exitbuildsystem) +if %answer%==7 (goto webview2tools) +if %answer%==8 (goto exitbuildsystem) @echo Invalid input, please try again. @@ -509,6 +508,84 @@ build-stable.cmd Pack :: =================================================================================================== +:webview2tools +cls + +echo WebView2 SDK Tools +echo. +echo 1. Setup WebView2 SDK +echo 2. Update WebView2 SDK +echo 3. Check WebView2 Version +echo 4. Go back to main menu +echo: +set /p answer="Enter number (1 - 4): " +if %answer%==1 (goto setupwebview2sdk) +if %answer%==2 (goto updatewebview2sdk) +if %answer%==3 (goto checkwebview2version) +if %answer%==4 (goto mainmenu) + +@echo Invalid input, please try again. + +pause + +goto webview2tools + +:: =================================================================================================== + +:setupwebview2sdk +cls + +echo Setting up WebView2 SDK for KryptonWebView2 control... +echo This will install the latest stable WebView2 SDK version. +echo. + +cd Scripts + +Setup-WebView2SDK.cmd + +cd .. + +pause + +goto webview2tools + +:: =================================================================================================== + +:updatewebview2sdk +cls + +echo Updating WebView2 SDK to latest version... +echo This will check for updates and install the newest stable version. +echo. + +cd Scripts + +Update-WebView2SDK.cmd + +cd .. + +pause + +goto webview2tools + +:: =================================================================================================== + +:checkwebview2version +cls + +echo Checking WebView2 SDK version... +echo. + +cd Scripts + +Check-WebView2Version.cmd + +cd .. + +pause + +goto webview2tools + :clearlogfiles :clearbinaries \ No newline at end of file