mirror of
https://github.com/microsoft/PowerToys.git
synced 2024-11-24 04:12:32 +08:00
[FileExplorerPreview] Move everything from WebBrowser to WebView2 (#17588)
* Move MarkdownPreviewHandler from WebBrowser to WebView2 * Disable context menu Open links in default browser * Update expect.txt * Move SvgPreviewHandler from WebBrowser to WebView2 * Migrate SvgThumbnailProvider from WebBrowser to WebView2 * Migrate CustomControlTest to WebView2 Remove WebBrowser related stuff * Update tests * Revert GetThumbnail return value Disable javascript dialogs in WebView2 for Svg thumbnail and preview * expect.txt * Increase timeout for Markdown tests * Add sleeps * Add zero check
This commit is contained in:
parent
cbd362cef1
commit
88517bfdf7
4
.github/actions/spell-check/expect.txt
vendored
4
.github/actions/spell-check/expect.txt
vendored
@ -65,7 +65,7 @@ APPICON
|
||||
appid
|
||||
appium
|
||||
APPLASTZONE
|
||||
applets
|
||||
Applets
|
||||
Applicationcan
|
||||
applicationframehost
|
||||
applog
|
||||
@ -303,7 +303,7 @@ constexpr
|
||||
contentdialog
|
||||
contentfiles
|
||||
CONTEXTHELP
|
||||
CONTEXTMENU
|
||||
contextmenu
|
||||
CONTEXTMENUHANDLER
|
||||
CONTROLL
|
||||
CONTROLPARENT
|
||||
|
@ -26,7 +26,6 @@ using System.Diagnostics.CodeAnalysis;
|
||||
[assembly: SuppressMessage("Microsoft.Design", "CA1009:DeclareEventHandlersCorrectly", Scope = "member", Target = "Microsoft.Templates.Core.Locations.TemplatesSynchronization.#SyncStatusChanged", Justification = "Using an Action<object, SyncStatusEventArgs> does not allow the required notation")]
|
||||
|
||||
// Non general suppressions
|
||||
[assembly: SuppressMessage("Microsoft.Globalization", "CA1303:Do not pass literals as localized parameters", Justification = "The WebBrowser is loading source code to be shown to the user. No localization required.", MessageId = "System.Windows.Controls.WebBrowser.NavigateToString(System.String)", Scope = "member", Target = "Microsoft.Templates.UI.Controls.CodeViewer.#UpdateCodeView(System.Func`2<System.String,System.String>,System.String,System.String,System.Boolean)")]
|
||||
[assembly: SuppressMessage("Microsoft.Globalization", "CA1303:Do not pass literals as localized parameters", Justification = "This is part of the markdown processing", MessageId = "System.Windows.Documents.Run.#ctor(System.String)", Scope = "member", Target = "Microsoft.Templates.UI.Controls.Markdown.#ImageInlineEvaluator(System.Text.RegularExpressions.Match)")]
|
||||
[assembly: SuppressMessage("Microsoft.Globalization", "CA1308:NormalizeStringsToUppercase", Justification = "We need to have the names of these keys in lowercase to be able to compare with the keys becoming form the template json. ContainsKey does not allow StringComparer specification to IgnoreCase", Scope = "member", Target = "Microsoft.Templates.Core.ITemplateInfoExtensions.#GetQueryableProperties(Microsoft.TemplateEngine.Abstractions.ITemplateInfo)")]
|
||||
[assembly: SuppressMessage("Microsoft.Globalization", "CA1308:NormalizeStringsToUppercase", Justification = "We need to have the names of these keys in lowercase to be able to compare with the keys becoming form the template json. ContainsKey does not allow StringComparer specification to IgnoreCase", Scope = "member", Target = "Microsoft.Templates.Core.Composition.CompositionQuery.#Match(System.Collections.Generic.IEnumerable`1<Microsoft.Templates.Core.Composition.QueryNode>,Microsoft.Templates.Core.Composition.QueryablePropertyDictionary)")]
|
||||
|
@ -26,7 +26,6 @@ using System.Diagnostics.CodeAnalysis;
|
||||
[assembly: SuppressMessage("Microsoft.Design", "CA1009:DeclareEventHandlersCorrectly", Scope = "member", Target = "Microsoft.Templates.Core.Locations.TemplatesSynchronization.#SyncStatusChanged", Justification = "Using an Action<object, SyncStatusEventArgs> does not allow the required notation")]
|
||||
|
||||
// Non general suppressions
|
||||
[assembly: SuppressMessage("Microsoft.Globalization", "CA1303:Do not pass literals as localized parameters", Justification = "The WebBrowser is loading source code to be shown to the user. No localization required.", MessageId = "System.Windows.Controls.WebBrowser.NavigateToString(System.String)", Scope = "member", Target = "Microsoft.Templates.UI.Controls.CodeViewer.#UpdateCodeView(System.Func`2<System.String,System.String>,System.String,System.String,System.Boolean)")]
|
||||
[assembly: SuppressMessage("Microsoft.Globalization", "CA1303:Do not pass literals as localized parameters", Justification = "This is part of the markdown processing", MessageId = "System.Windows.Documents.Run.#ctor(System.String)", Scope = "member", Target = "Microsoft.Templates.UI.Controls.Markdown.#ImageInlineEvaluator(System.Text.RegularExpressions.Match)")]
|
||||
[assembly: SuppressMessage("Microsoft.Globalization", "CA1308:NormalizeStringsToUppercase", Justification = "We need to have the names of these keys in lowercase to be able to compare with the keys becoming form the template json. ContainsKey does not allow StringComparer specification to IgnoreCase", Scope = "member", Target = "Microsoft.Templates.Core.ITemplateInfoExtensions.#GetQueryableProperties(Microsoft.TemplateEngine.Abstractions.ITemplateInfo)")]
|
||||
[assembly: SuppressMessage("Microsoft.Globalization", "CA1308:NormalizeStringsToUppercase", Justification = "We need to have the names of these keys in lowercase to be able to compare with the keys becoming form the template json. ContainsKey does not allow StringComparer specification to IgnoreCase", Scope = "member", Target = "Microsoft.Templates.Core.Composition.CompositionQuery.#Match(System.Collections.Generic.IEnumerable`1<Microsoft.Templates.Core.Composition.QueryNode>,Microsoft.Templates.Core.Composition.QueryablePropertyDictionary)")]
|
||||
|
@ -15,7 +15,7 @@
|
||||
<PropertyGroup>
|
||||
<ProjectGuid>{6A71162E-FC4C-4A2C-B90F-3CF94F59A9BB}</ProjectGuid>
|
||||
<RootNamespace>Microsoft.PowerToys.PreviewHandler.Markdown</RootNamespace>
|
||||
<TargetFramework>net6.0-windows</TargetFramework>
|
||||
<TargetFramework>net6.0-windows10.0.18362.0</TargetFramework>
|
||||
<EnableComHosting>true</EnableComHosting>
|
||||
<IntermediateOutputPath>$(SolutionDir)$(Platform)\$(Configuration)\obj\$(AssemblyName)\</IntermediateOutputPath>
|
||||
<AssemblyName>PowerToys.MarkdownPreviewHandler</AssemblyName>
|
||||
@ -45,6 +45,7 @@
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.Web.WebView2" Version="1.0.1150.38" />
|
||||
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
|
@ -5,6 +5,8 @@
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.IO.Abstractions;
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Windows.Forms;
|
||||
using Common;
|
||||
@ -12,7 +14,10 @@ using Markdig;
|
||||
using Microsoft.PowerToys.PreviewHandler.Markdown.Properties;
|
||||
using Microsoft.PowerToys.PreviewHandler.Markdown.Telemetry.Events;
|
||||
using Microsoft.PowerToys.Telemetry;
|
||||
using Microsoft.Web.WebView2.Core;
|
||||
using Microsoft.Web.WebView2.WinForms;
|
||||
using PreviewHandlerCommon;
|
||||
using Windows.System;
|
||||
|
||||
namespace Microsoft.PowerToys.PreviewHandler.Markdown
|
||||
{
|
||||
@ -53,13 +58,40 @@ namespace Microsoft.PowerToys.PreviewHandler.Markdown
|
||||
/// <summary>
|
||||
/// Extended Browser Control to display markdown html.
|
||||
/// </summary>
|
||||
private WebBrowserExt _browser;
|
||||
private WebView2 _browser;
|
||||
|
||||
/// <summary>
|
||||
/// WebView2 Environment
|
||||
/// </summary>
|
||||
private CoreWebView2Environment _webView2Environment;
|
||||
|
||||
/// <summary>
|
||||
/// Name of the virtual host
|
||||
/// </summary>
|
||||
public const string VirtualHostName = "PowerToysLocalMarkdown";
|
||||
|
||||
/// <summary>
|
||||
/// True if external image is blocked, false otherwise.
|
||||
/// </summary>
|
||||
private bool _infoBarDisplayed;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the path of the current assembly.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Source: https://stackoverflow.com/a/283917/14774889
|
||||
/// </remarks>
|
||||
public static string AssemblyDirectory
|
||||
{
|
||||
get
|
||||
{
|
||||
string codeBase = Assembly.GetExecutingAssembly().Location;
|
||||
UriBuilder uri = new UriBuilder(codeBase);
|
||||
string path = Uri.UnescapeDataString(uri.Path);
|
||||
return Path.GetDirectoryName(path);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="MarkdownPreviewHandlerControl"/> class.
|
||||
/// </summary>
|
||||
@ -103,25 +135,52 @@ namespace Microsoft.PowerToys.PreviewHandler.Markdown
|
||||
string parsedMarkdown = Markdig.Markdown.ToHtml(fileText, pipeline);
|
||||
string markdownHTML = $"{htmlHeader}{parsedMarkdown}{htmlFooter}";
|
||||
|
||||
_browser = new WebView2()
|
||||
{
|
||||
Dock = DockStyle.Fill,
|
||||
};
|
||||
|
||||
_browser.NavigationStarting += async (object sender, CoreWebView2NavigationStartingEventArgs args) =>
|
||||
{
|
||||
if (args.Uri != null && args.IsUserInitiated)
|
||||
{
|
||||
args.Cancel = true;
|
||||
await Launcher.LaunchUriAsync(new Uri(args.Uri));
|
||||
}
|
||||
};
|
||||
|
||||
InvokeOnControlThread(() =>
|
||||
{
|
||||
_browser = new WebBrowserExt
|
||||
ConfiguredTaskAwaitable<CoreWebView2Environment>.ConfiguredTaskAwaiter
|
||||
webView2EnvironmentAwaiter = CoreWebView2Environment
|
||||
.CreateAsync(userDataFolder: System.Environment.GetEnvironmentVariable("USERPROFILE") +
|
||||
"\\AppData\\LocalLow\\Microsoft\\PowerToys\\MarkdownPreview-Temp")
|
||||
.ConfigureAwait(true).GetAwaiter();
|
||||
webView2EnvironmentAwaiter.OnCompleted(() =>
|
||||
{
|
||||
DocumentText = markdownHTML,
|
||||
Dock = DockStyle.Fill,
|
||||
IsWebBrowserContextMenuEnabled = false,
|
||||
ScriptErrorsSuppressed = true,
|
||||
ScrollBarsEnabled = true,
|
||||
AllowNavigation = false,
|
||||
};
|
||||
Controls.Add(_browser);
|
||||
InvokeOnControlThread(async () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
_webView2Environment = webView2EnvironmentAwaiter.GetResult();
|
||||
await _browser.EnsureCoreWebView2Async(_webView2Environment).ConfigureAwait(true);
|
||||
await _browser.CoreWebView2.AddScriptToExecuteOnDocumentCreatedAsync("window.addEventListener('contextmenu', window => {window.preventDefault();});");
|
||||
_browser.CoreWebView2.SetVirtualHostNameToFolderMapping(VirtualHostName, AssemblyDirectory, CoreWebView2HostResourceAccessKind.Allow);
|
||||
_browser.NavigateToString(markdownHTML);
|
||||
Controls.Add(_browser);
|
||||
|
||||
if (_infoBarDisplayed)
|
||||
{
|
||||
_infoBar = GetTextBoxControl(Resources.BlockedImageInfoText);
|
||||
Resize += FormResized;
|
||||
Controls.Add(_infoBar);
|
||||
}
|
||||
if (_infoBarDisplayed)
|
||||
{
|
||||
_infoBar = GetTextBoxControl(Resources.BlockedImageInfoText);
|
||||
Resize += FormResized;
|
||||
Controls.Add(_infoBar);
|
||||
}
|
||||
}
|
||||
catch (NullReferenceException)
|
||||
{
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
PowerToysTelemetry.Log.WriteEvent(new MarkdownFilePreviewed());
|
||||
|
@ -31,7 +31,7 @@
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.Web.WebView2" Version="1.0.1108.44" />
|
||||
<PackageReference Include="Microsoft.Web.WebView2" Version="1.0.1150.38" />
|
||||
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
|
@ -5,6 +5,8 @@
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices.ComTypes;
|
||||
using System.Windows.Forms;
|
||||
using Common;
|
||||
@ -12,6 +14,8 @@ using Common.Utilities;
|
||||
using Microsoft.PowerToys.PreviewHandler.Svg.Telemetry.Events;
|
||||
using Microsoft.PowerToys.PreviewHandler.Svg.Utilities;
|
||||
using Microsoft.PowerToys.Telemetry;
|
||||
using Microsoft.Web.WebView2.Core;
|
||||
using Microsoft.Web.WebView2.WinForms;
|
||||
using PreviewHandlerCommon;
|
||||
|
||||
namespace Microsoft.PowerToys.PreviewHandler.Svg
|
||||
@ -22,9 +26,36 @@ namespace Microsoft.PowerToys.PreviewHandler.Svg
|
||||
public class SvgPreviewControl : FormHandlerControl
|
||||
{
|
||||
/// <summary>
|
||||
/// Extended Browser Control to display Svg.
|
||||
/// WebView2 Control to display Svg.
|
||||
/// </summary>
|
||||
private WebBrowserExt _browser;
|
||||
private WebView2 _browser;
|
||||
|
||||
/// <summary>
|
||||
/// WebView2 Environment
|
||||
/// </summary>
|
||||
private CoreWebView2Environment _webView2Environment;
|
||||
|
||||
/// <summary>
|
||||
/// Name of the virtual host
|
||||
/// </summary>
|
||||
public const string VirtualHostName = "PowerToysLocalSvg";
|
||||
|
||||
/// <summary>
|
||||
/// Gets the path of the current assembly.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Source: https://stackoverflow.com/a/283917/14774889
|
||||
/// </remarks>
|
||||
public static string AssemblyDirectory
|
||||
{
|
||||
get
|
||||
{
|
||||
string codeBase = Assembly.GetExecutingAssembly().Location;
|
||||
UriBuilder uri = new UriBuilder(codeBase);
|
||||
string path = Uri.UnescapeDataString(uri.Path);
|
||||
return Path.GetDirectoryName(path);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Text box to display the information about blocked elements from Svg.
|
||||
@ -73,7 +104,6 @@ namespace Microsoft.PowerToys.PreviewHandler.Svg
|
||||
catch (Exception ex)
|
||||
#pragma warning restore CA1031 // Do not catch general exception types
|
||||
{
|
||||
_browser.ScrollBarsEnabled = true;
|
||||
PowerToysTelemetry.Log.WriteEvent(new SvgFilePreviewError { Message = ex.Message });
|
||||
}
|
||||
|
||||
@ -90,7 +120,7 @@ namespace Microsoft.PowerToys.PreviewHandler.Svg
|
||||
AddTextBoxControl(Properties.Resource.BlockedElementInfoText);
|
||||
}
|
||||
|
||||
AddBrowserControl(svgData);
|
||||
AddWebViewControl(svgData);
|
||||
Resize += FormResized;
|
||||
base.DoPreview(dataSource);
|
||||
PowerToysTelemetry.Log.WriteEvent(new SvgFilePreviewed());
|
||||
@ -129,19 +159,38 @@ namespace Microsoft.PowerToys.PreviewHandler.Svg
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a Web Browser Control to Control Collection.
|
||||
/// Adds a WebView2 Control to Control Collection.
|
||||
/// </summary>
|
||||
/// <param name="svgData">Svg to display on Browser Control.</param>
|
||||
private void AddBrowserControl(string svgData)
|
||||
private void AddWebViewControl(string svgData)
|
||||
{
|
||||
_browser = new WebBrowserExt();
|
||||
_browser.DocumentText = svgData;
|
||||
_browser = new WebView2();
|
||||
_browser.Dock = DockStyle.Fill;
|
||||
_browser.IsWebBrowserContextMenuEnabled = false;
|
||||
_browser.ScriptErrorsSuppressed = true;
|
||||
_browser.ScrollBarsEnabled = false;
|
||||
_browser.AllowNavigation = false;
|
||||
Controls.Add(_browser);
|
||||
|
||||
ConfiguredTaskAwaitable<CoreWebView2Environment>.ConfiguredTaskAwaiter
|
||||
webView2EnvironmentAwaiter = CoreWebView2Environment
|
||||
.CreateAsync(userDataFolder: System.Environment.GetEnvironmentVariable("USERPROFILE") +
|
||||
"\\AppData\\LocalLow\\Microsoft\\PowerToys\\SvgPreview-Temp")
|
||||
.ConfigureAwait(true).GetAwaiter();
|
||||
webView2EnvironmentAwaiter.OnCompleted(() =>
|
||||
{
|
||||
InvokeOnControlThread(async () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
_webView2Environment = webView2EnvironmentAwaiter.GetResult();
|
||||
await _browser.EnsureCoreWebView2Async(_webView2Environment).ConfigureAwait(true);
|
||||
await _browser.CoreWebView2.AddScriptToExecuteOnDocumentCreatedAsync("window.addEventListener('contextmenu', window => {window.preventDefault();});");
|
||||
_browser.CoreWebView2.SetVirtualHostNameToFolderMapping(VirtualHostName, AssemblyDirectory, CoreWebView2HostResourceAccessKind.Allow);
|
||||
_browser.CoreWebView2.Settings.AreDefaultScriptDialogsEnabled = false;
|
||||
_browser.NavigateToString(svgData);
|
||||
Controls.Add(_browser);
|
||||
}
|
||||
catch (NullReferenceException)
|
||||
{
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -49,6 +49,7 @@
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.Web.WebView2" Version="1.0.1150.38" />
|
||||
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
|
@ -117,7 +117,7 @@ namespace Microsoft.PowerToys.PreviewHandler.Svg.Utilities
|
||||
|
||||
string centering = "position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);";
|
||||
|
||||
// Because WebBrowser class is based on IE version that do not support max-width and max-height extra CSS is needed for it to work.
|
||||
// max-width and max-height not supported. Extra CSS is needed for it to work.
|
||||
string scaling = $"max-width: {width} ; max-height: {height} ;";
|
||||
scaling += $" _height:expression(this.scrollHeight > {heightR} ? \" {height}\" : \"auto\"); _width:expression(this.scrollWidth > {widthR} ? \"{width}\" : \"auto\");";
|
||||
|
||||
|
@ -6,13 +6,15 @@ using System.Drawing;
|
||||
using System.Drawing.Drawing2D;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.InteropServices.ComTypes;
|
||||
using System.Windows.Forms;
|
||||
using Common.ComInterlop;
|
||||
using Common.Utilities;
|
||||
using PreviewHandlerCommon;
|
||||
using Microsoft.Web.WebView2.Core;
|
||||
using Microsoft.Web.WebView2.WinForms;
|
||||
|
||||
namespace Microsoft.PowerToys.ThumbnailHandler.Svg
|
||||
{
|
||||
@ -22,7 +24,7 @@ namespace Microsoft.PowerToys.ThumbnailHandler.Svg
|
||||
[Guid("36B27788-A8BB-4698-A756-DF9F11F64F84")]
|
||||
[ClassInterface(ClassInterfaceType.None)]
|
||||
[ComVisible(true)]
|
||||
public class SvgThumbnailProvider : IInitializeWithStream, IThumbnailProvider
|
||||
public class SvgThumbnailProvider : IInitializeWithStream, IThumbnailProvider, IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the stream object to access file.
|
||||
@ -35,135 +37,116 @@ namespace Microsoft.PowerToys.ThumbnailHandler.Svg
|
||||
private const uint MaxThumbnailSize = 10000;
|
||||
|
||||
/// <summary>
|
||||
/// Captures an image representation of browser contents.
|
||||
/// WebView2 Control to display Svg.
|
||||
/// </summary>
|
||||
/// <param name="browser">The WebBrowser instance rendering the SVG.</param>
|
||||
/// <param name="rectangle">The client rectangle to capture from.</param>
|
||||
/// <param name="backgroundColor">The default background color to apply.</param>
|
||||
/// <returns>A Bitmap representing the browser contents.</returns>
|
||||
public static Bitmap GetBrowserContentImage(WebBrowser browser, Rectangle rectangle, Color backgroundColor)
|
||||
private WebView2 _browser;
|
||||
|
||||
/// <summary>
|
||||
/// WebView2 Environment
|
||||
/// </summary>
|
||||
private CoreWebView2Environment _webView2Environment;
|
||||
|
||||
/// <summary>
|
||||
/// Name of the virtual host
|
||||
/// </summary>
|
||||
public const string VirtualHostName = "PowerToysLocalSvgThumbnail";
|
||||
|
||||
/// <summary>
|
||||
/// Gets the path of the current assembly.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Source: https://stackoverflow.com/a/283917/14774889
|
||||
/// </remarks>
|
||||
public static string AssemblyDirectory
|
||||
{
|
||||
Bitmap image = new Bitmap(rectangle.Width, rectangle.Height);
|
||||
using (Graphics graphics = Graphics.FromImage(image))
|
||||
get
|
||||
{
|
||||
IntPtr deviceContextHandle = IntPtr.Zero;
|
||||
RECT rect = new RECT
|
||||
{
|
||||
Left = rectangle.Left,
|
||||
Top = rectangle.Top,
|
||||
Right = rectangle.Right,
|
||||
Bottom = rectangle.Bottom,
|
||||
};
|
||||
|
||||
graphics.Clear(backgroundColor);
|
||||
|
||||
try
|
||||
{
|
||||
deviceContextHandle = graphics.GetHdc();
|
||||
|
||||
IViewObject viewObject = browser?.ActiveXInstance as IViewObject;
|
||||
viewObject.Draw(1, -1, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, deviceContextHandle, ref rect, IntPtr.Zero, IntPtr.Zero, 0);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (deviceContextHandle != IntPtr.Zero)
|
||||
{
|
||||
graphics.ReleaseHdc(deviceContextHandle);
|
||||
}
|
||||
}
|
||||
string codeBase = Assembly.GetExecutingAssembly().Location;
|
||||
UriBuilder uri = new UriBuilder(codeBase);
|
||||
string path = Uri.UnescapeDataString(uri.Path);
|
||||
return Path.GetDirectoryName(path);
|
||||
}
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Wrap the SVG markup in HTML with a meta tag to ensure the
|
||||
/// WebBrowser control is in Edge mode to enable SVG rendering.
|
||||
/// We also set the padding and margin for the body to zero as
|
||||
/// there is a default margin of 8.
|
||||
/// Render SVG using WebView2 control, capture the WebView2
|
||||
/// preview and create Bitmap out of it.
|
||||
/// </summary>
|
||||
/// <param name="content">The content to render.</param>
|
||||
/// <param name="cx">The maximum thumbnail size, in pixels.</param>
|
||||
/// <returns>A thumbnail of the rendered content.</returns>
|
||||
public static Bitmap GetThumbnail(string content, uint cx)
|
||||
public Bitmap GetThumbnail(string content, uint cx)
|
||||
{
|
||||
if (cx > MaxThumbnailSize)
|
||||
if (cx == 0 || cx > MaxThumbnailSize || string.IsNullOrEmpty(content) || !content.Contains("svg"))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
Bitmap thumbnail = null;
|
||||
|
||||
// Wrap the SVG content in HTML in IE Edge mode so we can ensure
|
||||
// we render properly.
|
||||
bool thumbnailDone = false;
|
||||
string wrappedContent = WrapSVGInHTML(content);
|
||||
using (WebBrowserExt browser = new WebBrowserExt())
|
||||
|
||||
_browser = new WebView2();
|
||||
_browser.Dock = DockStyle.Fill;
|
||||
_browser.Visible = true;
|
||||
_browser.Width = (int)cx;
|
||||
_browser.Height = (int)cx;
|
||||
_browser.NavigationCompleted += async (object sender, CoreWebView2NavigationCompletedEventArgs args) =>
|
||||
{
|
||||
browser.Dock = DockStyle.Fill;
|
||||
browser.IsWebBrowserContextMenuEnabled = false;
|
||||
browser.ScriptErrorsSuppressed = true;
|
||||
browser.ScrollBarsEnabled = false;
|
||||
browser.AllowNavigation = false;
|
||||
browser.Width = (int)cx;
|
||||
browser.Height = (int)cx;
|
||||
browser.DocumentText = wrappedContent;
|
||||
|
||||
// Wait for the browser to render the content.
|
||||
while (browser.IsBusy || browser.ReadyState != WebBrowserReadyState.Complete)
|
||||
var a = await _browser.ExecuteScriptAsync($"document.getElementsByTagName('svg')[0].viewBox;");
|
||||
if (a != null)
|
||||
{
|
||||
Application.DoEvents();
|
||||
await _browser.ExecuteScriptAsync($"document.getElementsByTagName('svg')[0].style = 'width:100%;height:100%';");
|
||||
}
|
||||
|
||||
// Check size of the rendered SVG.
|
||||
var svg = browser.Document.GetElementsByTagName("svg").Cast<HtmlElement>().FirstOrDefault();
|
||||
if (svg != null)
|
||||
MemoryStream ms = new MemoryStream();
|
||||
await _browser.CoreWebView2.CapturePreviewAsync(CoreWebView2CapturePreviewImageFormat.Png, ms);
|
||||
thumbnail = new Bitmap(ms);
|
||||
|
||||
if (thumbnail.Width != cx && thumbnail.Height != cx && thumbnail.Width != 0 && thumbnail.Height != 0)
|
||||
{
|
||||
var viewBox = svg.GetAttribute("viewbox");
|
||||
if (viewBox != null)
|
||||
{
|
||||
// Update the svg style to override any width or height explicit settings
|
||||
// Setting to 100% width and height will allow to scale to our intended size
|
||||
// Otherwise, we would end up with a scaled up blurry image.
|
||||
svg.Style = "width:100%;height:100%";
|
||||
|
||||
// Wait for the browser to render the content.
|
||||
while (browser.IsBusy || browser.ReadyState != WebBrowserReadyState.Complete)
|
||||
{
|
||||
Application.DoEvents();
|
||||
}
|
||||
}
|
||||
|
||||
// Update the size of the browser control to fit the SVG
|
||||
// in the visible viewport.
|
||||
browser.Width = svg.OffsetRectangle.Width;
|
||||
browser.Height = svg.OffsetRectangle.Height;
|
||||
|
||||
// Wait for the browser to render the content.
|
||||
while (browser.IsBusy || browser.ReadyState != WebBrowserReadyState.Complete)
|
||||
{
|
||||
Application.DoEvents();
|
||||
}
|
||||
|
||||
// Capture the image of the SVG from the browser.
|
||||
thumbnail = GetBrowserContentImage(browser, svg.OffsetRectangle, Color.White);
|
||||
if (thumbnail.Width != cx && thumbnail.Height != cx)
|
||||
{
|
||||
// We are not the appropriate size for caller. Resize now while
|
||||
// respecting the aspect ratio.
|
||||
float scale = Math.Min((float)cx / thumbnail.Width, (float)cx / thumbnail.Height);
|
||||
int scaleWidth = (int)(thumbnail.Width * scale);
|
||||
int scaleHeight = (int)(thumbnail.Height * scale);
|
||||
thumbnail = ResizeImage(thumbnail, scaleWidth, scaleHeight);
|
||||
}
|
||||
// We are not the appropriate size for caller. Resize now while
|
||||
// respecting the aspect ratio.
|
||||
float scale = Math.Min((float)cx / thumbnail.Width, (float)cx / thumbnail.Height);
|
||||
int scaleWidth = (int)(thumbnail.Width * scale);
|
||||
int scaleHeight = (int)(thumbnail.Height * scale);
|
||||
thumbnail = ResizeImage(thumbnail, scaleWidth, scaleHeight);
|
||||
}
|
||||
|
||||
thumbnailDone = true;
|
||||
};
|
||||
|
||||
ConfiguredTaskAwaitable<CoreWebView2Environment>.ConfiguredTaskAwaiter
|
||||
webView2EnvironmentAwaiter = CoreWebView2Environment
|
||||
.CreateAsync(userDataFolder: System.Environment.GetEnvironmentVariable("USERPROFILE") +
|
||||
"\\AppData\\LocalLow\\Microsoft\\PowerToys\\SvgThumbnailPreview-Temp")
|
||||
.ConfigureAwait(true).GetAwaiter();
|
||||
webView2EnvironmentAwaiter.OnCompleted(async () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
_webView2Environment = webView2EnvironmentAwaiter.GetResult();
|
||||
await _browser.EnsureCoreWebView2Async(_webView2Environment).ConfigureAwait(true);
|
||||
await _browser.CoreWebView2.AddScriptToExecuteOnDocumentCreatedAsync("window.addEventListener('contextmenu', window => {window.preventDefault();});");
|
||||
_browser.CoreWebView2.SetVirtualHostNameToFolderMapping(VirtualHostName, AssemblyDirectory, CoreWebView2HostResourceAccessKind.Allow);
|
||||
_browser.CoreWebView2.Settings.AreDefaultScriptDialogsEnabled = false;
|
||||
_browser.NavigateToString(wrappedContent);
|
||||
}
|
||||
catch (NullReferenceException)
|
||||
{
|
||||
}
|
||||
});
|
||||
|
||||
while (thumbnailDone == false)
|
||||
{
|
||||
Application.DoEvents();
|
||||
}
|
||||
|
||||
return thumbnail;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Wrap the SVG markup in HTML with a meta tag to ensure the
|
||||
/// WebBrowser control is in Edge mode to enable SVG rendering.
|
||||
/// Wrap the SVG markup in HTML with a meta tag to render it
|
||||
/// using WebView2 control.
|
||||
/// We also set the padding and margin for the body to zero as
|
||||
/// there is a default margin of 8.
|
||||
/// </summary>
|
||||
@ -261,5 +244,10 @@ namespace Microsoft.PowerToys.ThumbnailHandler.Svg
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -25,6 +25,7 @@
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.Web.WebView2" Version="1.0.1150.38" />
|
||||
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
|
@ -2,18 +2,23 @@
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Threading;
|
||||
using System.Windows.Forms;
|
||||
using Microsoft.PowerToys.PreviewHandler.Markdown;
|
||||
using Microsoft.PowerToys.STATestExtension;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using PreviewHandlerCommon;
|
||||
using Microsoft.Web.WebView2.WinForms;
|
||||
|
||||
namespace MarkdownPreviewHandlerUnitTests
|
||||
{
|
||||
[STATestClass]
|
||||
public class MarkdownPreviewHandlerTest
|
||||
{
|
||||
private static readonly int TenSecondsInMilliseconds = 10000;
|
||||
private static readonly int SleepTimeInMilliseconds = 200;
|
||||
|
||||
[TestMethod]
|
||||
public void MarkdownPreviewHandlerControlAddsBrowserToFormWhenDoPreviewIsCalled()
|
||||
{
|
||||
@ -23,9 +28,17 @@ namespace MarkdownPreviewHandlerUnitTests
|
||||
// Act
|
||||
markdownPreviewHandlerControl.DoPreview<string>("HelperFiles/MarkdownWithExternalImage.txt");
|
||||
|
||||
int beforeTick = Environment.TickCount;
|
||||
|
||||
while (markdownPreviewHandlerControl.Controls.Count == 0 && Environment.TickCount < beforeTick + TenSecondsInMilliseconds)
|
||||
{
|
||||
Application.DoEvents();
|
||||
Thread.Sleep(SleepTimeInMilliseconds);
|
||||
}
|
||||
|
||||
// Assert
|
||||
Assert.AreEqual(2, markdownPreviewHandlerControl.Controls.Count);
|
||||
Assert.IsInstanceOfType(markdownPreviewHandlerControl.Controls[0], typeof(WebBrowserExt));
|
||||
Assert.IsInstanceOfType(markdownPreviewHandlerControl.Controls[0], typeof(WebView2));
|
||||
}
|
||||
}
|
||||
|
||||
@ -38,6 +51,14 @@ namespace MarkdownPreviewHandlerUnitTests
|
||||
// Act
|
||||
markdownPreviewHandlerControl.DoPreview<string>("HelperFiles/MarkdownWithExternalImage.txt");
|
||||
|
||||
int beforeTick = Environment.TickCount;
|
||||
|
||||
while (markdownPreviewHandlerControl.Controls.Count == 0 && Environment.TickCount < beforeTick + TenSecondsInMilliseconds)
|
||||
{
|
||||
Application.DoEvents();
|
||||
Thread.Sleep(SleepTimeInMilliseconds);
|
||||
}
|
||||
|
||||
// Assert
|
||||
Assert.AreEqual(2, markdownPreviewHandlerControl.Controls.Count);
|
||||
Assert.IsInstanceOfType(markdownPreviewHandlerControl.Controls[1], typeof(RichTextBox));
|
||||
@ -53,6 +74,14 @@ namespace MarkdownPreviewHandlerUnitTests
|
||||
// Act
|
||||
markdownPreviewHandlerControl.DoPreview<string>("HelperFiles/MarkdownWithHTMLImageTag.txt");
|
||||
|
||||
int beforeTick = Environment.TickCount;
|
||||
|
||||
while (markdownPreviewHandlerControl.Controls.Count < 2 && Environment.TickCount < beforeTick + TenSecondsInMilliseconds)
|
||||
{
|
||||
Application.DoEvents();
|
||||
Thread.Sleep(SleepTimeInMilliseconds);
|
||||
}
|
||||
|
||||
// Assert
|
||||
Assert.AreEqual(2, markdownPreviewHandlerControl.Controls.Count);
|
||||
Assert.IsInstanceOfType(markdownPreviewHandlerControl.Controls[1], typeof(RichTextBox));
|
||||
@ -68,9 +97,17 @@ namespace MarkdownPreviewHandlerUnitTests
|
||||
// Act
|
||||
markdownPreviewHandlerControl.DoPreview<string>("HelperFiles/MarkdownWithScript.txt");
|
||||
|
||||
int beforeTick = Environment.TickCount;
|
||||
|
||||
while (markdownPreviewHandlerControl.Controls.Count == 0 && Environment.TickCount < beforeTick + TenSecondsInMilliseconds)
|
||||
{
|
||||
Application.DoEvents();
|
||||
Thread.Sleep(SleepTimeInMilliseconds);
|
||||
}
|
||||
|
||||
// Assert
|
||||
Assert.AreEqual(1, markdownPreviewHandlerControl.Controls.Count);
|
||||
Assert.IsInstanceOfType(markdownPreviewHandlerControl.Controls[0], typeof(WebBrowserExt));
|
||||
Assert.IsInstanceOfType(markdownPreviewHandlerControl.Controls[0], typeof(WebView2));
|
||||
}
|
||||
}
|
||||
|
||||
@ -83,14 +120,17 @@ namespace MarkdownPreviewHandlerUnitTests
|
||||
// Act
|
||||
markdownPreviewHandlerControl.DoPreview<string>("HelperFiles/MarkdownWithExternalImage.txt");
|
||||
|
||||
int beforeTick = Environment.TickCount;
|
||||
|
||||
while (markdownPreviewHandlerControl.Controls.Count < 2 && Environment.TickCount < beforeTick + TenSecondsInMilliseconds)
|
||||
{
|
||||
Application.DoEvents();
|
||||
Thread.Sleep(SleepTimeInMilliseconds);
|
||||
}
|
||||
|
||||
// Assert
|
||||
Assert.IsInstanceOfType(markdownPreviewHandlerControl.Controls[0], typeof(WebBrowserExt));
|
||||
Assert.IsNotNull(((WebBrowser)markdownPreviewHandlerControl.Controls[0]).DocumentText);
|
||||
Assert.AreEqual(DockStyle.Fill, ((WebBrowser)markdownPreviewHandlerControl.Controls[0]).Dock);
|
||||
Assert.AreEqual(false, ((WebBrowser)markdownPreviewHandlerControl.Controls[0]).IsWebBrowserContextMenuEnabled);
|
||||
Assert.AreEqual(true, ((WebBrowser)markdownPreviewHandlerControl.Controls[0]).ScriptErrorsSuppressed);
|
||||
Assert.AreEqual(true, ((WebBrowser)markdownPreviewHandlerControl.Controls[0]).ScrollBarsEnabled);
|
||||
Assert.AreEqual(false, ((WebBrowser)markdownPreviewHandlerControl.Controls[0]).AllowNavigation);
|
||||
Assert.IsInstanceOfType(markdownPreviewHandlerControl.Controls[0], typeof(WebView2));
|
||||
Assert.AreEqual(DockStyle.Fill, ((WebView2)markdownPreviewHandlerControl.Controls[0]).Dock);
|
||||
}
|
||||
}
|
||||
|
||||
@ -103,6 +143,14 @@ namespace MarkdownPreviewHandlerUnitTests
|
||||
// Act
|
||||
markdownPreviewHandlerControl.DoPreview<string>("HelperFiles/MarkdownWithExternalImage.txt");
|
||||
|
||||
int beforeTick = Environment.TickCount;
|
||||
|
||||
while (markdownPreviewHandlerControl.Controls.Count == 0 && Environment.TickCount < beforeTick + TenSecondsInMilliseconds)
|
||||
{
|
||||
Application.DoEvents();
|
||||
Thread.Sleep(SleepTimeInMilliseconds);
|
||||
}
|
||||
|
||||
// Assert
|
||||
Assert.IsInstanceOfType(markdownPreviewHandlerControl.Controls[1], typeof(RichTextBox));
|
||||
Assert.IsNotNull(((RichTextBox)markdownPreviewHandlerControl.Controls[1]).Text);
|
||||
|
@ -11,7 +11,7 @@
|
||||
<ProjectGuid>{A2B51B8B-8F90-424E-BC97-F9AB7D76CA1A}</ProjectGuid>
|
||||
<RootNamespace>PreviewPaneUnitTests</RootNamespace>
|
||||
<AssemblyName>PreviewPaneUnitTests</AssemblyName>
|
||||
<TargetFramework>net6.0-windows</TargetFramework>
|
||||
<TargetFramework>net6.0-windows10.0.18362.0</TargetFramework>
|
||||
<ProjectTypeGuids>{3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
|
||||
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
|
||||
<ReferencePath>$(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages</ReferencePath>
|
||||
|
@ -25,9 +25,6 @@
|
||||
<PackageReference Include="MSTest.TestAdapter" Version="2.2.3" />
|
||||
<PackageReference Include="MSTest.TestFramework" Version="2.2.3" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Update="WebBrowserExtUnitTests.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="..\..\..\codeAnalysis\GlobalSuppressions.cs" Link="GlobalSuppressions.cs" />
|
||||
<Compile Include="..\STATestClassAttribute.cs" Link="STATestClassAttribute.cs" />
|
||||
|
@ -1,60 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Reflection;
|
||||
using Common;
|
||||
using Microsoft.PowerToys.STATestExtension;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using PreviewHandlerCommon;
|
||||
|
||||
namespace PreviewHandlerCommonUnitTests
|
||||
{
|
||||
[STATestClass]
|
||||
public class WebBrowserExtUnitTests : WebBrowserExt
|
||||
{
|
||||
private const string DISPIDAMBIENTDLCONTROL = "[DISPID=-5512]";
|
||||
|
||||
[TestMethod]
|
||||
public void InvokeMemberShouldSetValidFlagsWhenCalledWithValidDispId()
|
||||
{
|
||||
// Arrange
|
||||
var extendedSite = CreateWebBrowserSiteBase() as WebBrowserSiteExt;
|
||||
|
||||
// Act
|
||||
var actualFlags = (int)extendedSite.InvokeMember(DISPIDAMBIENTDLCONTROL, BindingFlags.InvokeMethod, null, null, null, null, null, null);
|
||||
|
||||
// Assert
|
||||
Assert.IsTrue((actualFlags & (int)WebBrowserDownloadControlFlags.PRAGMA_NO_CACHE) >= 0);
|
||||
Assert.IsTrue((actualFlags & (int)WebBrowserDownloadControlFlags.FORCEOFFLINE) >= 0);
|
||||
Assert.IsTrue((actualFlags & (int)WebBrowserDownloadControlFlags.NO_CLIENTPULL) >= 0);
|
||||
Assert.IsTrue((actualFlags & (int)WebBrowserDownloadControlFlags.NO_SCRIPTS) >= 0);
|
||||
Assert.IsTrue((actualFlags & (int)WebBrowserDownloadControlFlags.NO_JAVA) >= 0);
|
||||
Assert.IsTrue((actualFlags & (int)WebBrowserDownloadControlFlags.NO_FRAMEDOWNLOAD) >= 0);
|
||||
Assert.IsTrue((actualFlags & (int)WebBrowserDownloadControlFlags.NOFRAMES) >= 0);
|
||||
Assert.IsTrue((actualFlags & (int)WebBrowserDownloadControlFlags.NO_DLACTIVEXCTLS) >= 0);
|
||||
Assert.IsTrue((actualFlags & (int)WebBrowserDownloadControlFlags.NO_RUNACTIVEXCTLS) >= 0);
|
||||
Assert.IsTrue((actualFlags & (int)WebBrowserDownloadControlFlags.NO_BEHAVIORS) >= 0);
|
||||
Assert.IsTrue((actualFlags & (int)WebBrowserDownloadControlFlags.SILENT) >= 0);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void InvokeMemberShouldOnlySetValidFlagsWhenCalledWithValidDispId()
|
||||
{
|
||||
// Arrange
|
||||
var extendedSite = CreateWebBrowserSiteBase() as WebBrowserSiteExt;
|
||||
|
||||
// Act
|
||||
var actualFlags = (int)extendedSite.InvokeMember(DISPIDAMBIENTDLCONTROL, BindingFlags.InvokeMethod, null, null, null, null, null, null);
|
||||
|
||||
// Assert
|
||||
Assert.IsTrue((actualFlags & (int)WebBrowserDownloadControlFlags.VIDEOS) == 0);
|
||||
Assert.IsTrue((actualFlags & (int)WebBrowserDownloadControlFlags.BGSOUNDS) == 0);
|
||||
Assert.IsTrue((actualFlags & (int)WebBrowserDownloadControlFlags.DOWNLOADONLY) == 0);
|
||||
Assert.IsTrue((actualFlags & (int)WebBrowserDownloadControlFlags.RESYNCHRONIZE) == 0);
|
||||
Assert.IsTrue((actualFlags & (int)WebBrowserDownloadControlFlags.NO_METACHARSET) == 0);
|
||||
Assert.IsTrue((actualFlags & (int)WebBrowserDownloadControlFlags.URL_ENCODING_DISABLE_UTF8) == 0);
|
||||
Assert.IsTrue((actualFlags & (uint)WebBrowserDownloadControlFlags.URL_ENCODING_ENABLE_UTF8) == 0);
|
||||
}
|
||||
}
|
||||
}
|
@ -7,12 +7,13 @@ using System.Drawing;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.InteropServices.ComTypes;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Windows.Forms;
|
||||
using Microsoft.PowerToys.PreviewHandler.Svg;
|
||||
using Microsoft.PowerToys.STATestExtension;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using Microsoft.Web.WebView2.WinForms;
|
||||
using Moq;
|
||||
using PreviewHandlerCommon;
|
||||
|
||||
namespace SvgPreviewHandlerUnitTests
|
||||
{
|
||||
@ -20,6 +21,9 @@ namespace SvgPreviewHandlerUnitTests
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "CA2201:Do not raise reserved exception types", Justification = "new Exception() is fine in test projects.")]
|
||||
public class SvgPreviewControlTests
|
||||
{
|
||||
private static readonly int ThreeSecondsInMilliseconds = 3000;
|
||||
private static readonly int SleepTimeInMilliseconds = 200;
|
||||
|
||||
[TestMethod]
|
||||
public void SvgPreviewControlShouldAddExtendedBrowserControlWhenDoPreviewCalled()
|
||||
{
|
||||
@ -29,14 +33,22 @@ namespace SvgPreviewHandlerUnitTests
|
||||
// Act
|
||||
svgPreviewControl.DoPreview(GetMockStream("<svg></svg>"));
|
||||
|
||||
int beforeTick = Environment.TickCount;
|
||||
|
||||
while (svgPreviewControl.Controls.Count == 0 && Environment.TickCount < beforeTick + ThreeSecondsInMilliseconds)
|
||||
{
|
||||
Application.DoEvents();
|
||||
Thread.Sleep(SleepTimeInMilliseconds);
|
||||
}
|
||||
|
||||
// Assert
|
||||
Assert.AreEqual(1, svgPreviewControl.Controls.Count);
|
||||
Assert.IsInstanceOfType(svgPreviewControl.Controls[0], typeof(WebBrowserExt));
|
||||
Assert.IsInstanceOfType(svgPreviewControl.Controls[0], typeof(WebView2));
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void SvgPreviewControlShouldSetDocumentStreamWhenDoPreviewCalled()
|
||||
public void SvgPreviewControlShouldFillDockForWebView2WhenDoPreviewCalled()
|
||||
{
|
||||
// Arrange
|
||||
using (var svgPreviewControl = new SvgPreviewControl())
|
||||
@ -44,80 +56,16 @@ namespace SvgPreviewHandlerUnitTests
|
||||
// Act
|
||||
svgPreviewControl.DoPreview(GetMockStream("<svg></svg>"));
|
||||
|
||||
// Assert
|
||||
Assert.IsNotNull(((WebBrowser)svgPreviewControl.Controls[0]).DocumentStream);
|
||||
}
|
||||
}
|
||||
int beforeTick = Environment.TickCount;
|
||||
|
||||
[TestMethod]
|
||||
public void SvgPreviewControlShouldDisableWebBrowserContextMenuWhenDoPreviewCalled()
|
||||
{
|
||||
// Arrange
|
||||
using (var svgPreviewControl = new SvgPreviewControl())
|
||||
{
|
||||
// Act
|
||||
svgPreviewControl.DoPreview(GetMockStream("<svg></svg>"));
|
||||
while (svgPreviewControl.Controls.Count == 0 && Environment.TickCount < beforeTick + ThreeSecondsInMilliseconds)
|
||||
{
|
||||
Application.DoEvents();
|
||||
Thread.Sleep(SleepTimeInMilliseconds);
|
||||
}
|
||||
|
||||
// Assert
|
||||
Assert.AreEqual(false, ((WebBrowser)svgPreviewControl.Controls[0]).IsWebBrowserContextMenuEnabled);
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void SvgPreviewControlShouldFillDockForWebBrowserWhenDoPreviewCalled()
|
||||
{
|
||||
// Arrange
|
||||
using (var svgPreviewControl = new SvgPreviewControl())
|
||||
{
|
||||
// Act
|
||||
svgPreviewControl.DoPreview(GetMockStream("<svg></svg>"));
|
||||
|
||||
// Assert
|
||||
Assert.AreEqual(DockStyle.Fill, ((WebBrowser)svgPreviewControl.Controls[0]).Dock);
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void SvgPreviewControlShouldSetScriptErrorsSuppressedPropertyWhenDoPreviewCalled()
|
||||
{
|
||||
// Arrange
|
||||
using (var svgPreviewControl = new SvgPreviewControl())
|
||||
{
|
||||
// Act
|
||||
svgPreviewControl.DoPreview(GetMockStream("<svg></svg>"));
|
||||
|
||||
// Assert
|
||||
Assert.AreEqual(true, ((WebBrowser)svgPreviewControl.Controls[0]).ScriptErrorsSuppressed);
|
||||
}
|
||||
}
|
||||
|
||||
// ToDo: fix unit test
|
||||
[Ignore]
|
||||
[TestMethod]
|
||||
public void SvgPreviewControlShouldSetScrollBarsEnabledPropertyWhenDoPreviewCalled()
|
||||
{
|
||||
// Arrange
|
||||
using (var svgPreviewControl = new SvgPreviewControl())
|
||||
{
|
||||
// Act
|
||||
svgPreviewControl.DoPreview(GetMockStream("<svg></svg>"));
|
||||
|
||||
// Assert
|
||||
Assert.AreEqual(true, ((WebBrowser)svgPreviewControl.Controls[0]).ScrollBarsEnabled);
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void SvgPreviewControlShouldDisableAllowNavigationWhenDoPreviewCalled()
|
||||
{
|
||||
// Arrange
|
||||
using (var svgPreviewControl = new SvgPreviewControl())
|
||||
{
|
||||
// Act
|
||||
svgPreviewControl.DoPreview(GetMockStream("<svg></svg>"));
|
||||
|
||||
// Assert
|
||||
Assert.AreEqual(false, ((WebBrowser)svgPreviewControl.Controls[0]).AllowNavigation);
|
||||
Assert.AreEqual(DockStyle.Fill, ((WebView2)svgPreviewControl.Controls[0]).Dock);
|
||||
}
|
||||
}
|
||||
|
||||
@ -134,6 +82,15 @@ namespace SvgPreviewHandlerUnitTests
|
||||
|
||||
// Act
|
||||
svgPreviewControl.DoPreview(mockStream.Object);
|
||||
|
||||
int beforeTick = Environment.TickCount;
|
||||
|
||||
while (svgPreviewControl.Controls.Count == 0 && Environment.TickCount < beforeTick + ThreeSecondsInMilliseconds)
|
||||
{
|
||||
Application.DoEvents();
|
||||
Thread.Sleep(SleepTimeInMilliseconds);
|
||||
}
|
||||
|
||||
var textBox = svgPreviewControl.Controls[0] as RichTextBox;
|
||||
|
||||
// Assert
|
||||
@ -159,6 +116,15 @@ namespace SvgPreviewHandlerUnitTests
|
||||
.Setup(x => x.Read(It.IsAny<byte[]>(), It.IsAny<int>(), It.IsAny<IntPtr>()))
|
||||
.Throws(new Exception());
|
||||
svgPreviewControl.DoPreview(mockStream.Object);
|
||||
|
||||
int beforeTick = Environment.TickCount;
|
||||
|
||||
while (svgPreviewControl.Controls.Count == 0 && Environment.TickCount < beforeTick + ThreeSecondsInMilliseconds)
|
||||
{
|
||||
Application.DoEvents();
|
||||
Thread.Sleep(SleepTimeInMilliseconds);
|
||||
}
|
||||
|
||||
var textBox = svgPreviewControl.Controls[0] as RichTextBox;
|
||||
var incrementParentControlWidth = 5;
|
||||
var initialParentWidth = svgPreviewControl.Width;
|
||||
@ -188,9 +154,17 @@ namespace SvgPreviewHandlerUnitTests
|
||||
// Act
|
||||
svgPreviewControl.DoPreview(GetMockStream(svgBuilder.ToString()));
|
||||
|
||||
int beforeTick = Environment.TickCount;
|
||||
|
||||
while (svgPreviewControl.Controls.Count < 2 && Environment.TickCount < beforeTick + ThreeSecondsInMilliseconds)
|
||||
{
|
||||
Application.DoEvents();
|
||||
Thread.Sleep(SleepTimeInMilliseconds);
|
||||
}
|
||||
|
||||
// Assert
|
||||
Assert.IsInstanceOfType(svgPreviewControl.Controls[0], typeof(RichTextBox));
|
||||
Assert.IsInstanceOfType(svgPreviewControl.Controls[1], typeof(WebBrowserExt));
|
||||
Assert.IsInstanceOfType(svgPreviewControl.Controls[1], typeof(WebView2));
|
||||
Assert.AreEqual(2, svgPreviewControl.Controls.Count);
|
||||
}
|
||||
}
|
||||
@ -210,8 +184,16 @@ namespace SvgPreviewHandlerUnitTests
|
||||
// Act
|
||||
svgPreviewControl.DoPreview(GetMockStream(svgBuilder.ToString()));
|
||||
|
||||
int beforeTick = Environment.TickCount;
|
||||
|
||||
while (svgPreviewControl.Controls.Count == 0 && Environment.TickCount < beforeTick + ThreeSecondsInMilliseconds)
|
||||
{
|
||||
Application.DoEvents();
|
||||
Thread.Sleep(SleepTimeInMilliseconds);
|
||||
}
|
||||
|
||||
// Assert
|
||||
Assert.IsInstanceOfType(svgPreviewControl.Controls[0], typeof(WebBrowserExt));
|
||||
Assert.IsInstanceOfType(svgPreviewControl.Controls[0], typeof(WebView2));
|
||||
Assert.AreEqual(1, svgPreviewControl.Controls.Count);
|
||||
}
|
||||
}
|
||||
@ -227,6 +209,15 @@ namespace SvgPreviewHandlerUnitTests
|
||||
svgBuilder.AppendLine("\t<script>alert(\"hello\")</script>");
|
||||
svgBuilder.AppendLine("</svg>");
|
||||
svgPreviewControl.DoPreview(GetMockStream(svgBuilder.ToString()));
|
||||
|
||||
int beforeTick = Environment.TickCount;
|
||||
|
||||
while (svgPreviewControl.Controls.Count == 0 && Environment.TickCount < beforeTick + ThreeSecondsInMilliseconds)
|
||||
{
|
||||
Application.DoEvents();
|
||||
Thread.Sleep(SleepTimeInMilliseconds);
|
||||
}
|
||||
|
||||
var textBox = svgPreviewControl.Controls[0] as RichTextBox;
|
||||
var incrementParentControlWidth = 5;
|
||||
var initialParentWidth = svgPreviewControl.Width;
|
||||
|
@ -7,6 +7,7 @@ using System.Drawing;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.InteropServices.ComTypes;
|
||||
using System.Text;
|
||||
using System.Windows.Forms;
|
||||
using Common.ComInterlop;
|
||||
using Microsoft.PowerToys.STATestExtension;
|
||||
using Microsoft.PowerToys.ThumbnailHandler.Svg;
|
||||
@ -27,8 +28,12 @@ namespace SvgThumbnailProviderUnitTests
|
||||
svgBuilder.AppendLine("\t</circle>");
|
||||
svgBuilder.AppendLine("</svg>");
|
||||
|
||||
Bitmap thumbnail = SvgThumbnailProvider.GetThumbnail(svgBuilder.ToString(), 256);
|
||||
Assert.IsTrue(thumbnail != null);
|
||||
SvgThumbnailProvider svgThumbnailProvider = new SvgThumbnailProvider();
|
||||
Bitmap thumbnail = svgThumbnailProvider.GetThumbnail(svgBuilder.ToString(), 256);
|
||||
|
||||
Assert.IsNotNull(thumbnail);
|
||||
Assert.IsTrue(thumbnail.Width > 0);
|
||||
Assert.IsTrue(thumbnail.Height > 0);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
@ -41,7 +46,8 @@ namespace SvgThumbnailProviderUnitTests
|
||||
svgBuilder.AppendLine("\t</circle>");
|
||||
svgBuilder.AppendLine("</svg>");
|
||||
|
||||
Bitmap thumbnail = SvgThumbnailProvider.GetThumbnail(svgBuilder.ToString(), 256);
|
||||
SvgThumbnailProvider svgThumbnailProvider = new SvgThumbnailProvider();
|
||||
Bitmap thumbnail = svgThumbnailProvider.GetThumbnail(svgBuilder.ToString(), 256);
|
||||
Assert.IsTrue(thumbnail != null);
|
||||
}
|
||||
|
||||
@ -51,21 +57,24 @@ namespace SvgThumbnailProviderUnitTests
|
||||
var svgBuilder = new StringBuilder();
|
||||
svgBuilder.AppendLine("<p>foo</p>");
|
||||
|
||||
Bitmap thumbnail = SvgThumbnailProvider.GetThumbnail(svgBuilder.ToString(), 256);
|
||||
SvgThumbnailProvider svgThumbnailProvider = new SvgThumbnailProvider();
|
||||
Bitmap thumbnail = svgThumbnailProvider.GetThumbnail(svgBuilder.ToString(), 256);
|
||||
Assert.IsTrue(thumbnail == null);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void CheckNoSvgEmptyStringShouldReturnNullBitmap()
|
||||
{
|
||||
Bitmap thumbnail = SvgThumbnailProvider.GetThumbnail(string.Empty, 256);
|
||||
SvgThumbnailProvider svgThumbnailProvider = new SvgThumbnailProvider();
|
||||
Bitmap thumbnail = svgThumbnailProvider.GetThumbnail(string.Empty, 256);
|
||||
Assert.IsTrue(thumbnail == null);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void CheckNoSvgNullStringShouldReturnNullBitmap()
|
||||
{
|
||||
Bitmap thumbnail = SvgThumbnailProvider.GetThumbnail(null, 256);
|
||||
SvgThumbnailProvider svgThumbnailProvider = new SvgThumbnailProvider();
|
||||
Bitmap thumbnail = svgThumbnailProvider.GetThumbnail(null, 256);
|
||||
Assert.IsTrue(thumbnail == null);
|
||||
}
|
||||
|
||||
@ -73,7 +82,8 @@ namespace SvgThumbnailProviderUnitTests
|
||||
public void CheckZeroSizedThumbnailShouldReturnNullBitmap()
|
||||
{
|
||||
string content = "<svg></svg>";
|
||||
Bitmap thumbnail = SvgThumbnailProvider.GetThumbnail(content, 0);
|
||||
SvgThumbnailProvider svgThumbnailProvider = new SvgThumbnailProvider();
|
||||
Bitmap thumbnail = svgThumbnailProvider.GetThumbnail(content, 0);
|
||||
Assert.IsTrue(thumbnail == null);
|
||||
}
|
||||
|
||||
@ -94,7 +104,8 @@ namespace SvgThumbnailProviderUnitTests
|
||||
svgBuilder.AppendLine("</body>");
|
||||
svgBuilder.AppendLine("</html>");
|
||||
|
||||
Bitmap thumbnail = SvgThumbnailProvider.GetThumbnail(svgBuilder.ToString(), 256);
|
||||
SvgThumbnailProvider svgThumbnailProvider = new SvgThumbnailProvider();
|
||||
Bitmap thumbnail = svgThumbnailProvider.GetThumbnail(svgBuilder.ToString(), 256);
|
||||
Assert.IsTrue(thumbnail != null);
|
||||
}
|
||||
|
||||
|
@ -23,7 +23,6 @@
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Include="..\..\..\codeAnalysis\GlobalSuppressions.cs" Link="GlobalSuppressions.cs" />
|
||||
<Compile Update="controls\WebBrowserExt.cs" />
|
||||
<Compile Update="examplehandler\CustomControlTest.cs" />
|
||||
<Compile Update="controls\FormHandlerControl.cs" />
|
||||
</ItemGroup>
|
||||
@ -39,6 +38,7 @@
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.Web.WebView2" Version="1.0.1150.38" />
|
||||
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
|
@ -120,7 +120,7 @@ namespace Common
|
||||
this.Controls.Clear();
|
||||
});
|
||||
|
||||
// Call garbage collection at the time of unloading of Preview. This is to mitigate issue with WebBrowser Control not able to dispose properly.
|
||||
// Call garbage collection at the time of unloading of Preview.
|
||||
// Which is preventing prevhost.exe to exit at the time of closing File explorer.
|
||||
// Preview Handlers run in a separate process from PowerToys. This will not affect the performance of other modules.
|
||||
// Mitigate the following Github issue: https://github.com/microsoft/PowerToys/issues/1468
|
||||
|
@ -1,112 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
|
||||
namespace Common
|
||||
{
|
||||
/// <summary>
|
||||
/// Flags to control download and execution in Web Browser Control.
|
||||
/// Values of flags are defined in mshtmdid.h in distributed Windows Sdk.
|
||||
/// </summary>
|
||||
[Flags]
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Naming", "CA1707:Identifiers should not contain underscores", Justification = "Interop, keeping stuff in sync")]
|
||||
public enum WebBrowserDownloadControlFlags : int
|
||||
{
|
||||
/// <summary>
|
||||
/// Images will be downloaded from the server if this flag is set.
|
||||
/// </summary>
|
||||
DLIMAGES = 0x00000010,
|
||||
|
||||
/// <summary>
|
||||
/// Videos will be downloaded from the server if this flag is set.
|
||||
/// </summary>
|
||||
VIDEOS = 0x00000020,
|
||||
|
||||
/// <summary>
|
||||
/// Background sounds will be downloaded from the server if this flag is set.
|
||||
/// </summary>
|
||||
BGSOUNDS = 0x00000040,
|
||||
|
||||
/// <summary>
|
||||
/// Scripts will not be executed.
|
||||
/// </summary>
|
||||
NO_SCRIPTS = 0x00000080,
|
||||
|
||||
/// <summary>
|
||||
/// Java applets will not be executed.
|
||||
/// </summary>
|
||||
NO_JAVA = 0x00000100,
|
||||
|
||||
/// <summary>
|
||||
/// ActiveX controls will not be executed.
|
||||
/// </summary>
|
||||
NO_RUNACTIVEXCTLS = 0x00000200,
|
||||
|
||||
/// <summary>
|
||||
/// ActiveX controls will not be downloaded.
|
||||
/// </summary>
|
||||
NO_DLACTIVEXCTLS = 0x00000400,
|
||||
|
||||
/// <summary>
|
||||
/// The page will only be downloaded, not displayed.
|
||||
/// </summary>
|
||||
DOWNLOADONLY = 0x00000800,
|
||||
|
||||
/// <summary>
|
||||
/// WebBrowser Control will download and parse a frameSet, but not the individual frame objects within the frameSet.
|
||||
/// </summary>
|
||||
NO_FRAMEDOWNLOAD = 0x00001000,
|
||||
|
||||
/// <summary>
|
||||
/// The server will be asked for update status. Cached files will be used if the server indicates that the cached information is up-to-date.
|
||||
/// </summary>
|
||||
RESYNCHRONIZE = 0x00002000,
|
||||
|
||||
/// <summary>
|
||||
/// Files will be re-downloaded from the server regardless of the update status of the files.
|
||||
/// </summary>
|
||||
PRAGMA_NO_CACHE = 0x00004000,
|
||||
|
||||
/// <summary>
|
||||
/// Behaviors are not downloaded and are disabled in the document.
|
||||
/// </summary>
|
||||
NO_BEHAVIORS = 0x00008000,
|
||||
|
||||
/// <summary>
|
||||
/// Character sets specified in meta elements are suppressed.
|
||||
/// </summary>
|
||||
NO_METACHARSET = 0x00010000,
|
||||
|
||||
/// <summary>
|
||||
/// The browsing component will disable UTF-8 encoding.
|
||||
/// </summary>
|
||||
URL_ENCODING_DISABLE_UTF8 = 0x00020000,
|
||||
|
||||
/// <summary>
|
||||
/// The browsing component will enable UTF-8 encoding.
|
||||
/// </summary>
|
||||
URL_ENCODING_ENABLE_UTF8 = 0x00040000,
|
||||
|
||||
/// <summary>
|
||||
/// No Documentation Available.
|
||||
/// </summary>
|
||||
NOFRAMES = 0x00080000,
|
||||
|
||||
/// <summary>
|
||||
/// WebBrowser Control always operates in offline mode.
|
||||
/// </summary>
|
||||
FORCEOFFLINE = 0x10000000,
|
||||
|
||||
/// <summary>
|
||||
/// No client pull operations will be performed.
|
||||
/// </summary>
|
||||
NO_CLIENTPULL = 0x20000000,
|
||||
|
||||
/// <summary>
|
||||
/// No user interface will be displayed during downloads.
|
||||
/// </summary>
|
||||
SILENT = 0x40000000,
|
||||
}
|
||||
}
|
@ -1,142 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Reflection;
|
||||
using System.Windows.Forms;
|
||||
using Common;
|
||||
|
||||
namespace PreviewHandlerCommon
|
||||
{
|
||||
/// <summary>
|
||||
/// Customized the WebBrowser to get control over what it downloads, displays and executes.
|
||||
/// </summary>
|
||||
public class WebBrowserExt : WebBrowser
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
protected override WebBrowserSiteBase CreateWebBrowserSiteBase()
|
||||
{
|
||||
// Returns instance of WebBrowserSiteExt.
|
||||
return new WebBrowserSiteExt(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Extend the WebBrowserSite with IDispatch implementation to handle the DISPID_AMBIENT_DLCONTROL.
|
||||
/// More details: https://docs.microsoft.com/en-us/previous-versions/windows/internet-explorer/ie-developer/platform-apis/aa770041(v=vs.85)?redirectedfrom=MSDN#controlling-download-and-execution.
|
||||
/// </summary>
|
||||
protected class WebBrowserSiteExt : WebBrowserSite, IReflect
|
||||
{
|
||||
// Dispid of DISPID_AMBIENT_DLCONTROL is defined in MsHtmdid.h header file in distributed Windows Sdk component.
|
||||
private const string DISPIDAMBIENTDLCONTROL = "[DISPID=-5512]";
|
||||
private WebBrowserExt browserExtControl;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="WebBrowserSiteExt"/> class.
|
||||
/// </summary>
|
||||
/// <param name="browserControl">Browser Control Instance pass to the site.</param>
|
||||
public WebBrowserSiteExt(WebBrowserExt browserControl)
|
||||
: base(browserControl)
|
||||
{
|
||||
this.browserExtControl = browserControl;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Type UnderlyingSystemType
|
||||
{
|
||||
get { return this.GetType(); }
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public object InvokeMember(string name, BindingFlags invokeAttr, Binder binder, object target, object[] args, ParameterModifier[] modifiers, CultureInfo culture, string[] namedParameters)
|
||||
{
|
||||
object result;
|
||||
|
||||
if (name != null && name.Equals(DISPIDAMBIENTDLCONTROL, StringComparison.Ordinal))
|
||||
{
|
||||
// Using InvariantCulture since this is used for web browser configurations
|
||||
result = Convert.ToInt32(
|
||||
WebBrowserDownloadControlFlags.DLIMAGES |
|
||||
WebBrowserDownloadControlFlags.PRAGMA_NO_CACHE |
|
||||
WebBrowserDownloadControlFlags.FORCEOFFLINE |
|
||||
WebBrowserDownloadControlFlags.NO_CLIENTPULL |
|
||||
WebBrowserDownloadControlFlags.NO_SCRIPTS |
|
||||
WebBrowserDownloadControlFlags.NO_JAVA |
|
||||
WebBrowserDownloadControlFlags.NO_FRAMEDOWNLOAD |
|
||||
WebBrowserDownloadControlFlags.NOFRAMES |
|
||||
WebBrowserDownloadControlFlags.NO_DLACTIVEXCTLS |
|
||||
WebBrowserDownloadControlFlags.NO_RUNACTIVEXCTLS |
|
||||
WebBrowserDownloadControlFlags.NO_BEHAVIORS |
|
||||
WebBrowserDownloadControlFlags.SILENT, CultureInfo.InvariantCulture);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = GetType().InvokeMember(name, invokeAttr, binder, target, args, modifiers, culture, namedParameters);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public FieldInfo[] GetFields(BindingFlags bindingAttr)
|
||||
{
|
||||
return this.GetType().GetFields(bindingAttr);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public MethodInfo[] GetMethods(BindingFlags bindingAttr)
|
||||
{
|
||||
return this.GetType().GetMethods(bindingAttr);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public PropertyInfo[] GetProperties(BindingFlags bindingAttr)
|
||||
{
|
||||
return this.GetType().GetProperties(bindingAttr);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public FieldInfo GetField(string name, BindingFlags bindingAttr)
|
||||
{
|
||||
return this.GetType().GetField(name, bindingAttr);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public MemberInfo[] GetMember(string name, BindingFlags bindingAttr)
|
||||
{
|
||||
return this.GetType().GetMember(name, bindingAttr);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public MemberInfo[] GetMembers(BindingFlags bindingAttr)
|
||||
{
|
||||
return this.GetType().GetMembers(bindingAttr);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public MethodInfo GetMethod(string name, BindingFlags bindingAttr)
|
||||
{
|
||||
return this.GetType().GetMethod(name, bindingAttr);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public MethodInfo GetMethod(string name, BindingFlags bindingAttr, Binder binder, Type[] types, ParameterModifier[] modifiers)
|
||||
{
|
||||
return this.GetType().GetMethod(name, bindingAttr, binder, types, modifiers);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public PropertyInfo GetProperty(string name, BindingFlags bindingAttr, Binder binder, Type returnType, Type[] types, ParameterModifier[] modifiers)
|
||||
{
|
||||
return this.GetType().GetProperty(name, bindingAttr, binder, returnType, types, modifiers);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public PropertyInfo GetProperty(string name, BindingFlags bindingAttr)
|
||||
{
|
||||
return this.GetType().GetProperty(name, bindingAttr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -3,7 +3,12 @@
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Windows.Forms;
|
||||
using Microsoft.Web.WebView2.Core;
|
||||
using Microsoft.Web.WebView2.WinForms;
|
||||
|
||||
namespace Common
|
||||
{
|
||||
@ -12,6 +17,38 @@ namespace Common
|
||||
/// </summary>
|
||||
public class CustomControlTest : FormHandlerControl
|
||||
{
|
||||
/// <summary>
|
||||
/// WebView2 Control to display Svg.
|
||||
/// </summary>
|
||||
private WebView2 _browser;
|
||||
|
||||
/// <summary>
|
||||
/// WebView2 Environment
|
||||
/// </summary>
|
||||
private CoreWebView2Environment _webView2Environment;
|
||||
|
||||
/// <summary>
|
||||
/// Name of the virtual host
|
||||
/// </summary>
|
||||
public const string VirtualHostName = "PowerToysLocalCustomControlTest";
|
||||
|
||||
/// <summary>
|
||||
/// Gets the path of the current assembly.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Source: https://stackoverflow.com/a/283917/14774889
|
||||
/// </remarks>
|
||||
public static string AssemblyDirectory
|
||||
{
|
||||
get
|
||||
{
|
||||
string codeBase = Assembly.GetExecutingAssembly().Location;
|
||||
UriBuilder uri = new UriBuilder(codeBase);
|
||||
string path = Uri.UnescapeDataString(uri.Path);
|
||||
return Path.GetDirectoryName(path);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Start the preview on the Control.
|
||||
/// </summary>
|
||||
@ -21,13 +58,41 @@ namespace Common
|
||||
this.InvokeOnControlThread(() =>
|
||||
{
|
||||
var filePath = dataSource as string;
|
||||
WebBrowser browser = new WebBrowser();
|
||||
|
||||
browser.DocumentText = "Test";
|
||||
browser.Navigate(new Uri(filePath));
|
||||
browser.Dock = DockStyle.Fill;
|
||||
browser.IsWebBrowserContextMenuEnabled = false;
|
||||
this.Controls.Add(browser);
|
||||
_browser = new WebView2();
|
||||
_browser.Dock = DockStyle.Fill;
|
||||
_browser.Visible = true;
|
||||
_browser.NavigationCompleted += (object sender, CoreWebView2NavigationCompletedEventArgs args) =>
|
||||
{
|
||||
// Put here logic needed after WebView2 control is done navigating to url/page
|
||||
};
|
||||
|
||||
ConfiguredTaskAwaitable<CoreWebView2Environment>.ConfiguredTaskAwaiter
|
||||
webView2EnvironmentAwaiter = CoreWebView2Environment
|
||||
.CreateAsync(userDataFolder: System.Environment.GetEnvironmentVariable("USERPROFILE") +
|
||||
"\\AppData\\LocalLow\\Microsoft\\PowerToys\\CustomControlTest-Temp")
|
||||
.ConfigureAwait(true).GetAwaiter();
|
||||
webView2EnvironmentAwaiter.OnCompleted(async () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
_webView2Environment = webView2EnvironmentAwaiter.GetResult();
|
||||
await _browser.EnsureCoreWebView2Async(_webView2Environment).ConfigureAwait(true);
|
||||
await _browser.CoreWebView2.AddScriptToExecuteOnDocumentCreatedAsync("window.addEventListener('contextmenu', window => {window.preventDefault();});");
|
||||
_browser.CoreWebView2.SetVirtualHostNameToFolderMapping(VirtualHostName, AssemblyDirectory, CoreWebView2HostResourceAccessKind.Allow);
|
||||
|
||||
// Navigate to page represented as a string
|
||||
_browser.NavigateToString("Test");
|
||||
|
||||
// Or navigate to Uri
|
||||
_browser.Source = new Uri(filePath);
|
||||
}
|
||||
catch (NullReferenceException)
|
||||
{
|
||||
}
|
||||
});
|
||||
|
||||
this.Controls.Add(_browser);
|
||||
base.DoPreview(dataSource);
|
||||
});
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user