-
Notifications
You must be signed in to change notification settings - Fork 1.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Correct issues with ApiInformation implementation #2305
Changes from 3 commits
a2996b6
ff3f92b
586cabb
193077d
4bc5d4c
3f4f305
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
// See the LICENSE file in the project root for more information. | ||
|
||
using System; | ||
using Windows.Foundation.Metadata; | ||
|
||
namespace Microsoft.Toolkit.Win32.UI.Controls.Interop.WinRT | ||
{ | ||
// .NET applications use a concept of Union WinMD, which is the union of all known types that exist in the Windows SDK | ||
// that correspond to the MaxVersionTested setting of the app. If you're running the app on a down-level platform, | ||
// ApiInformation will tell you the API doesn't exist, but .NET can still JIT methods based on the Union WinMD and | ||
// perform some reflection tasks. If you actually try to call the API you will get a MissingMethodException at runtime | ||
// because the API doesn't really exist. | ||
// A different problem can occur if you include a higher-versioned .NET library inside a lower-versioned app and try to run | ||
// it on the higher-versioned build of the OS. In this case, ApiInformation will succeed because the type exists in the | ||
// system metadata, but .NET will throw a MissingMethodException at runtime because the type didn't exist in the Union WinMD | ||
// used to build the app. | ||
public static class ApiInformationExtensions | ||
{ | ||
public static void ExecuteIfPropertyPresent(string typeName, string propertyName, Action action) | ||
{ | ||
if (ApiInformation.IsPropertyPresent(typeName, propertyName)) | ||
{ | ||
try | ||
{ | ||
action(); | ||
} | ||
catch (MissingMethodException) | ||
{ | ||
} | ||
} | ||
} | ||
|
||
public static T ExecuteIfPropertyPresent<T>(string typeName, string propertyName, Func<T> action) | ||
{ | ||
if (ApiInformation.IsPropertyPresent(typeName, propertyName)) | ||
{ | ||
try | ||
{ | ||
return action(); | ||
} | ||
catch (MissingMethodException) | ||
{ | ||
} | ||
} | ||
|
||
return default(T); | ||
} | ||
|
||
public static void ExecuteIfMethodPresent(string typeName, string methodName, Action action) | ||
{ | ||
if (ApiInformation.IsMethodPresent(typeName, methodName)) | ||
{ | ||
try | ||
{ | ||
action(); | ||
} | ||
catch (MissingMethodException) | ||
{ | ||
} | ||
} | ||
} | ||
|
||
public static void ExecuteIfMethodPresent(string typeName, string methodName, uint inputParameterCount, Action action) | ||
{ | ||
if (ApiInformation.IsMethodPresent(typeName, methodName, inputParameterCount)) | ||
{ | ||
try | ||
{ | ||
action(); | ||
} | ||
catch (MissingMethodException) | ||
{ | ||
} | ||
} | ||
} | ||
|
||
public static void ExecuteIfEventPresent(string typeName, string eventName, Action action) | ||
{ | ||
if (ApiInformation.IsEventPresent(typeName, eventName)) | ||
{ | ||
try | ||
{ | ||
action(); | ||
} | ||
catch (MissingMethodException) | ||
{ | ||
} | ||
} | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -44,6 +44,7 @@ namespace Microsoft.Toolkit.Win32.UI.Controls.Interop.WinRT | |
internal sealed class WebViewControlHost : IDisposable | ||
{ | ||
private const string LocalContentIdentifier = "LocalContent"; | ||
private const string WinRtType = "Windows.Web.UI.Interop.WebViewControl"; | ||
|
||
[SecurityCritical] | ||
private WebViewControl _webViewControl; | ||
|
@@ -291,13 +292,11 @@ private bool NavigatingToAboutBlank | |
|
||
internal void AddPreLoadedScript(string script) | ||
{ | ||
if (ApiInformation.IsMethodPresent( | ||
"Windows.Web.UI.Interop.WebViewControl", | ||
ApiInformationExtensions.ExecuteIfMethodPresent( | ||
WinRtType, | ||
"AddPreLoadedScript", | ||
1)) | ||
{ | ||
_webViewControl?.AddPreLoadedScript(script); | ||
} | ||
1, | ||
() => { _webViewControl?.AddPreLoadedScript(script); }); | ||
} | ||
|
||
internal Uri BuildStream(string contentIdentifier, string relativePath) | ||
|
@@ -1067,15 +1066,15 @@ private void SubscribeEvents() | |
_webViewControl.UnsupportedUriSchemeIdentified += OnUnsupportedUriSchemeIdentified; | ||
_webViewControl.UnviewableContentIdentified += OnUnviewableContentIdentified; | ||
|
||
if (ApiInformation.IsEventPresent("Windows.Web.UI.Interop", "GotFocus")) | ||
{ | ||
_webViewControl.GotFocus += OnGotFocus; | ||
} | ||
ApiInformationExtensions.ExecuteIfEventPresent( | ||
WinRtType, | ||
"GotFocus", | ||
() => { _webViewControl.GotFocus += OnGotFocus; }); | ||
|
||
if (ApiInformation.IsEventPresent("Windows.Web.UI.Interop", "LostFocus")) | ||
{ | ||
_webViewControl.LostFocus += OnLostFocus; | ||
} | ||
ApiInformationExtensions.ExecuteIfEventPresent( | ||
WinRtType, | ||
"LostFocus", | ||
() => { _webViewControl.GotFocus += OnLostFocus; }); | ||
} | ||
|
||
[SecurityCritical] | ||
|
@@ -1115,15 +1114,15 @@ private void UnsubscribeEvents() | |
_webViewControl.UnsupportedUriSchemeIdentified -= OnUnsupportedUriSchemeIdentified; | ||
_webViewControl.UnviewableContentIdentified -= OnUnviewableContentIdentified; | ||
|
||
if (ApiInformation.IsEventPresent("Windows.Web.UI.Interop", "GotFocus")) | ||
{ | ||
_webViewControl.GotFocus -= OnGotFocus; | ||
} | ||
ApiInformationExtensions.ExecuteIfEventPresent( | ||
WinRtType, | ||
"GotFocus", | ||
() => { _webViewControl.GotFocus -= OnGotFocus; }); | ||
|
||
if (ApiInformation.IsEventPresent("Windows.Web.UI.Interop", "LostFocus")) | ||
{ | ||
_webViewControl.LostFocus -= OnLostFocus; | ||
} | ||
ApiInformationExtensions.ExecuteIfEventPresent( | ||
WinRtType, | ||
"LostFocus", | ||
() => { _webViewControl.GotFocus -= OnLostFocus; }); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should be LostFocus? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fixed in 4bc5d4c |
||
} | ||
|
||
private void UnsubscribeProcessExited() | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -17,6 +17,8 @@ namespace Microsoft.Toolkit.Win32.UI.Controls.Interop.WinRT | |
/// </summary> | ||
public sealed class WebViewControlProcess | ||
{ | ||
private const string WinRtType = "Windows.Web.UI.Interop.WebViewControlProcessOptions"; | ||
|
||
[SecurityCritical] | ||
private readonly Windows.Web.UI.Interop.WebViewControlProcess _process; | ||
|
||
|
@@ -69,14 +71,10 @@ public string Partition | |
{ | ||
get | ||
{ | ||
if (ApiInformation.IsPropertyPresent( | ||
"Windows.Web.UI.Interop.WebViewControlProcessOptions", | ||
"Partition")) | ||
{ | ||
return _process.Partition; | ||
} | ||
|
||
return string.Empty; | ||
return ApiInformationExtensions.ExecuteIfPropertyPresent( | ||
WinRtType, | ||
"Partition", | ||
() => _process.Partition) ?? string.Empty; | ||
} | ||
} | ||
|
||
|
@@ -94,14 +92,10 @@ public string UserAgent | |
{ | ||
get | ||
{ | ||
if (ApiInformation.IsPropertyPresent( | ||
"Windows.Web.UI.Interop.WebViewControlProcessOptions", | ||
"UserAgent")) | ||
{ | ||
return _process.UserAgent; | ||
} | ||
|
||
return string.Empty; | ||
return ApiInformationExtensions.ExecuteIfPropertyPresent( | ||
WinRtType, | ||
"Partition", | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. UserAgent? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should be replaced to, no? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It was in 193077d |
||
() => _process.Partition) ?? string.Empty; | ||
} | ||
} | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
// See the LICENSE file in the project root for more information. | ||
|
||
using Microsoft.Toolkit.Win32.UI.Controls.Test.WebView.Shared; | ||
using Microsoft.VisualStudio.TestTools.UnitTesting; | ||
using Should; | ||
|
||
namespace Microsoft.Toolkit.Win32.UI.Controls.Test.WinForms.WebView.FunctionalTests.UserAgent | ||
{ | ||
[TestClass] | ||
public class Given_a_WebView : HostFormWebViewContextSpecification | ||
{ | ||
private string _userAgent; | ||
|
||
protected override void Given() | ||
{ | ||
base.Given(); | ||
|
||
WebView.NavigationCompleted += (o, e) => | ||
{ | ||
var wv = o as Controls.WinForms.WebView; | ||
_userAgent = wv.Process.UserAgent; | ||
|
||
Form.Close(); | ||
}; | ||
} | ||
|
||
protected override void When() | ||
{ | ||
NavigateAndWaitForFormClose(TestConstants.Uris.ExampleCom); | ||
} | ||
|
||
|
||
[TestMethod] | ||
public void UserAgent_accessed_without_exception() | ||
{ | ||
_userAgent.ShouldEqual(string.Empty); | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should be LostFocus
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in 4bc5d4c