Skip to content
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

Backport WebView2 to WinUI2 #5708

Merged
merged 13 commits into from
Aug 22, 2021
Merged

Backport WebView2 to WinUI2 #5708

merged 13 commits into from
Aug 22, 2021

Conversation

jevansaks
Copy link
Member

@jevansaks jevansaks commented Aug 17, 2021

This is a backport of the WinUI3 control and tests into WinUI2. Notable differences from the experience you get in WinUI3 via WinAppSDK are:

  • This change adds a nuspec dependency from Microsoft.UI.Xaml onto WebView2's nupkg. In WinAppSDK the winrt implementation dlls are carried in the WinAppSDK runtime. We may change to do that as a follow-up.
  • In WinUI3 the Focus related methods were moved so that WebView2 can derive from FrameworkElement. We don't have that in OS XAML so WebView2 control derives from Control instead. 🤷

WinUI2 also compiles and supports Arm32, but WebView2 package does not because there is no WebView2 runtime for Arm32. I've asked the WebView2 folks to consider adding at least the type information (with stub implementation), but I don't know if/when that will happen. As such I have made the build conditional so that the Arm32 version does not include WebView2 control. Consumers will need to write conditional code as well if they support Arm32 and want to use WebView2.

Fixes #5610

@ghost ghost added the needs-triage Issue needs to be triaged by the area owners label Aug 17, 2021
@jevansaks
Copy link
Member Author

/azp run

@azure-pipelines
Copy link

Azure Pipelines successfully started running 1 pipeline(s).

@ranjeshj ranjeshj added area-WebView team-Rendering Issue for the Rendering team labels Aug 17, 2021
@jevansaks
Copy link
Member Author

/azp run

@azure-pipelines
Copy link

Azure Pipelines successfully started running 1 pipeline(s).

@jevansaks
Copy link
Member Author

/azp run

@azure-pipelines
Copy link

Azure Pipelines successfully started running 1 pipeline(s).

@jevansaks
Copy link
Member Author

/azp run

@azure-pipelines
Copy link

Azure Pipelines successfully started running 1 pipeline(s).

{
if (textbox.Value != expectedValue)
{
return;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shouldn't this assert/throw/fail the test?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmmm .. I don't know. This is what it looks like in WinUI3's code as well. @DmitriyKomin ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch. This function does two things (1)wait for textbox to attain a new value, and then (2) match that against expectedString (or the negation of it).

In the two places we use it, looks like it mostly just depends on part (1) - if the textbox value, changes then things are good, we don't depend on (2)... I am not sure that's true 100% of the time it's called, and also there could be new usages in the future expecting the matching part to work correctly...

In short, I agree this should be changed to return a bool reflecting the matching result.

dev/WebView2/WebView2.h Show resolved Hide resolved
dev/WebView2/WebView2AutomationPeer.cpp Outdated Show resolved Hide resolved
dev/WebView2/WebView2AutomationPeer.cpp Show resolved Hide resolved
dev/WebView2/WebView2AutomationPeer.h Outdated Show resolved Hide resolved
Comment on lines +2820 to +2843
public static uint PW_RENDERFULLCONTENT = 2;
[DllImport("user32.dll")] public static extern bool PrintWindow(IntPtr hWnd, IntPtr hdc, uint flags);
[DllImport("user32.dll")] public static extern IntPtr GetDC(IntPtr hWnd);
[DllImport("user32.dll")] public static extern IntPtr ReleaseDC(IntPtr hWnd, IntPtr hdc);
[DllImport("user32.dll", CharSet = CharSet.Unicode)] public static extern IntPtr FindWindowEx(IntPtr parentHandle, IntPtr childAfter, string className, string windowTitle);
[DllImport("user32.dll")] public static extern int GetWindowRect(IntPtr hWnd, ref RECT rectangle);
[DllImport("user32.dll")] public static extern int GetDpiForWindow([In] IntPtr hWnd);

[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
public int Left; // x position of upper-left corner
public int Top; // y position of upper-left corner
public int Right; // x position of lower-right corner
public int Bottom; // y position of lower-right corner
}

[DllImport("gdi32.dll")] public static extern IntPtr CreateCompatibleDC(IntPtr hdc);
[DllImport("gdi32.dll")] public static extern bool DeleteDC(IntPtr hdc);
[DllImport("gdi32.dll")] public static extern IntPtr CreateCompatibleBitmap(IntPtr hdc, int width, int height);
[DllImport("gdi32.dll")] public static extern IntPtr SelectObject(IntPtr hdc, IntPtr obj);
[DllImport("gdi32.dll")] public static extern bool DeleteObject(IntPtr obj);
[DllImport("gdi32.dll")] public static extern uint GetPixel(IntPtr hdc, int x, int y);
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit, we could be using win32metadata instead : )

}
}

private static bool AreEqualIgnoringSpace(string string1, string string2)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit, can probably use Uri.EscapeUriString instead?

"(async function() { " +
"let result = await window.chrome.webview.hostObjects.bridge.AnotherObject.Prop; " +
"window.chrome.webview.postMessage(result); })();");
// Listen for WebMessageReceived
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mark as TODO / file an issue?

public static Uri GetTestPageUri(string testPageName)
{
string localAppDataPath = AppDataPaths.GetDefault().LocalAppData;
string fullUri = @"file:///" + localAppDataPath + @"/" + testPageName;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit you can make this a little more readable with an interpolated string

Suggested change
string fullUri = @"file:///" + localAppDataPath + @"/" + testPageName;
string fullUri = $"file:///{localAppDataPath}/{testPageName}";

#include <winuser.h>
#include <uiautomationclient.h>

using namespace Microsoft::WRL;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

curious, could we not use wrl and use the cppwinrt winrt:: types instead?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting, I suspect this is stale, since I don't recall seeing any WRL usage in this file. Let me try to remove.

void WebView2::CreateMissingAnaheimWarning()
{
auto warning = winrt::TextBlock();
warning.Text(L"A suitable version of Microsoft Edge WebView2 Runtime was not detected. ");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shouldn't these strings come from resources / be localized?

float leftVal = inputProperties.ContactRect().X * m_rasterizationScale;
float topVal = inputProperties.ContactRect().Y * m_rasterizationScale;

winrt::Windows::Foundation::Rect outputPt_touchContact(static_cast<float>(leftVal), static_cast<float>(topVal), static_cast<float>(width), static_cast<float>(height));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these are already floats, can remove the casts. same below.

dev/WebView2/WebView2.cpp Show resolved Hide resolved
LRESULT result = ::SendMessageW(GetActiveInputWindowHwnd(), message, wparam, lparam);
if (!result)
{
winrt::check_hresult(HRESULT_FROM_WIN32(::GetLastError()));
Copy link
Member

@asklar asklar Aug 18, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

noexcept with check_hresult #ByDesign

dev/dll/Microsoft.UI.Xaml.vcxproj Outdated Show resolved Hide resolved
@jevansaks
Copy link
Member Author

/azp run

@azure-pipelines
Copy link

Azure Pipelines successfully started running 1 pipeline(s).

@jevansaks
Copy link
Member Author

/azp run

@azure-pipelines
Copy link

Azure Pipelines successfully started running 1 pipeline(s).

@jevansaks
Copy link
Member Author

/azp run

@azure-pipelines
Copy link

Azure Pipelines successfully started running 1 pipeline(s).

{
auto coreWindowInterop = coreWindow.as<ICoreWindowInterop>();
winrt::check_hresult(coreWindowInterop->get_WindowHandle(&m_xamlHostHwnd));
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happens in the context of OS Xaml islands / DWXS? I belive the CoreWindow will exist, but is not used for rendering... WebView2 will fail in some way. Should we early out to avoid unsafe behavior? Also, is there an issue/task to track WebView2 in island?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is just to get it working in UWP. We can have a follow-up to figure out how (if at all) to make it work in islands. I suspect there will be other things that need to be done.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

agree with getting it to work on UWP first and figuring out islands post "1.0".

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Having said that, an error message would be good if possible :)

if (m_visual)
{
winrt::float2 newSize = winrt::float2(width * m_rasterizationScale, height * m_rasterizationScale);
winrt::float3 newScale = winrt::float3(1.0f / m_rasterizationScale, 1.0f / m_rasterizationScale, 1.0);
Copy link
Contributor

@DmitriyKomin DmitriyKomin Aug 20, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Extract duplicatd code #WontFix

outputMatrix.m44 = 1.0f;

return outputMatrix;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is no longer used (was needed for older input forwarding API). Please remove.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about you remove in WinUI3 first and then i can copy those deltas over here?

WebView2::WebView2()
{
if (HMODULE user32module = LoadLibraryW(L"user32.dll"))
{
Copy link
Member

@asklar asklar Aug 20, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit, GetModuleHandle since user32 will have already been loaded (also gets rid of needing to free the hmodule) #Resolved

@DmitriyKomin
Copy link
Contributor

DmitriyKomin commented Aug 20, 2021

                string installerArgs_WV2Runtime = "/silent /install";

remove comments since we aren't useing mini_installer here


In reply to: 902955384


In reply to: 902955384


Refers to: dev/WebView2/InteractionTests/WebView2Tests.cs:147 in 1ffea83. [](commit_id = 1ffea83, deletion_comment = False)

Copy link
Member

@asklar asklar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

main remaining thing for me is to please make sure the noexcept/throws are reasonable (i.e. does it make sense to [not] bubble exceptions up to the app)

@DmitriyKomin
Copy link
Contributor

DmitriyKomin commented Aug 20, 2021

Per discussion with @jevansaks and @asklar , some of the comments made by @asklar and myself are existing issues in WinUI3 codebase and that are lower priority. I will capture these for fixing in WinUI3 codebase (and porting the changes back to WinUI2).

@jevansaks
Copy link
Member Author

/azp run

@azure-pipelines
Copy link

Azure Pipelines successfully started running 1 pipeline(s).

@jevansaks
Copy link
Member Author

/azp run

@azure-pipelines
Copy link

Azure Pipelines successfully started running 1 pipeline(s).

@jevansaks jevansaks merged commit 0bd0d22 into main Aug 22, 2021
@jevansaks jevansaks deleted the user/jevansaks/webview2 branch August 22, 2021 20:01
@EP012014
Copy link

Congratulations!

@michael-hawker
Copy link
Collaborator

How's the extra dependency going to work for an app that doesn't use WebView2? Will it be optimized out or increase the footprint of all apps using WinUI 2?

@jevansaks
Copy link
Member Author

How's the extra dependency going to work for an app that doesn't use WebView2? Will it be optimized out or increase the footprint of all apps using WinUI 2?

The dlls are relatively small (~500KB). For now it's getting copied into the consuming apps. We are discussing alternatives, since WinUI3 is already doing this slightly differently by including the WebView2 client-side dlls in the WinAppSDK framework package.

@codendone codendone removed the needs-triage Issue needs to be triaged by the area owners label Sep 2, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-WebView team-Rendering Issue for the Rendering team
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Proposal: Bringing WebView2 to WinUI 2
9 participants