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

Import CefSharp.Wpf.HwndHost into main repository. #4981

Merged
merged 13 commits into from
Jan 17, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
113 changes: 113 additions & 0 deletions CefSharp.Test/Wpf.HwndHost/WpfBrowserTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
// Copyright © 2017 The CefSharp Authors. All rights reserved.
//
// Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.

using System;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Interop;
using CefSharp.Example;
using CefSharp.Wpf.HwndHost;
using Xunit;
using Xunit.Abstractions;

namespace CefSharp.Test.Wpf.HwndHost
{
//NOTE: All Test classes must be part of this collection as it manages the Cef Initialize/Shutdown lifecycle
[Collection(CefSharpFixtureCollection.Key)]
[BrowserRefCountDebugging(typeof(ChromiumWebBrowser))]
public class WpfBrowserTests
{
[DllImport("user32.dll")]
private static extern IntPtr SetParent(IntPtr hwnd, IntPtr hwndNewParent);

private const int HWND_MESSAGE = -3;

private readonly ITestOutputHelper output;
private readonly CefSharpFixture fixture;

public WpfBrowserTests(ITestOutputHelper output, CefSharpFixture fixture)
{
this.fixture = fixture;
this.output = output;
}

[WpfFact]
public async Task ShouldWorkWhenLoadingGoogle()
{
var window = CreateAndShowHiddenWindow();

using (var browser = new ChromiumWebBrowser("www.google.com"))
{
window.Content = browser;

await browser.WaitForInitialLoadAsync();
var mainFrame = browser.GetMainFrame();

Assert.True(mainFrame.IsValid);
Assert.Contains("www.google", mainFrame.Url);

output.WriteLine("Url {0}", mainFrame.Url);
}
}

[WpfFact]
public async Task ShouldWorkWhenLoadUrlAsyncImmediately()
{
var window = CreateAndShowHiddenWindow();

using (var browser = new ChromiumWebBrowser(string.Empty))
{
window.Content = browser;

var response = await browser.LoadUrlAsync("www.google.com");
var mainFrame = browser.GetMainFrame();

Assert.True(response.Success);
Assert.True(mainFrame.IsValid);
Assert.Contains("www.google", mainFrame.Url);

output.WriteLine("Url {0}", mainFrame.Url);
}
}

[WpfFact]
public async Task ShouldRespectDisposed()
{
var window = CreateAndShowHiddenWindow();

ChromiumWebBrowser browser;

using (browser = new ChromiumWebBrowser(CefExample.DefaultUrl))
{
window.Content = browser;

await browser.WaitForInitialLoadAsync();
}

Assert.True(browser.IsDisposed);

var ex = Assert.Throws<ObjectDisposedException>(() =>
{
browser.Copy();
});
}

private static Window CreateAndShowHiddenWindow()
{
var window = new Window();
window.Width = 1024;
window.Height = 768;

var helper = new WindowInteropHelper(window);

helper.EnsureHandle();

SetParent(helper.Handle, (IntPtr)HWND_MESSAGE);

window.Show();
return window;
}
}
}
6 changes: 6 additions & 0 deletions CefSharp.Wpf.HwndHost.Example/App.config
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.2" />
</startup>
</configuration>
11 changes: 11 additions & 0 deletions CefSharp.Wpf.HwndHost.Example/App.xaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<Application x:Class="CefSharp.Wpf.HwndHost.Example.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:converter="clr-namespace:CefSharp.Wpf.HwndHost.Example.Converter"
StartupUri="MainWindow.xaml">
<Application.Resources>
<converter:TitleConverter x:Key="TitleConverter"/>
<converter:EnvironmentConverter x:Key="EnvironmentConverter" />
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
</Application.Resources>
</Application>
62 changes: 62 additions & 0 deletions CefSharp.Wpf.HwndHost.Example/App.xaml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
// Copyright © 2019 The CefSharp Authors. All rights reserved.
//
// Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.

using System;
using System.IO;
using System.Windows;
using CefSharp.Wpf.HwndHost.Handler;

namespace CefSharp.Wpf.HwndHost.Example
{
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : Application
{
public App()
{
#if !NETCOREAPP3_1_OR_GREATER
CefRuntime.SubscribeAnyCpuAssemblyResolver();
#endif
}

protected override void OnStartup(StartupEventArgs e)
{
var settings = new CefSettings()
{
//By default CefSharp will use an in-memory cache, you need to specify a Cache Folder to persist data
CachePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "CefSharp\\Cache")
};

//Example of setting a command line argument
//Enables WebRTC
// - CEF Doesn't currently support permissions on a per browser basis see https://bitbucket.org/chromiumembedded/cef/issues/2582/allow-run-time-handling-of-media-access
// - CEF Doesn't currently support displaying a UI for media access permissions
//
//NOTE: WebRTC Device Id's aren't persisted as they are in Chrome see https://bitbucket.org/chromiumembedded/cef/issues/2064/persist-webrtc-deviceids-across-restart
settings.CefCommandLineArgs.Add("enable-media-stream");
//https://peter.sh/experiments/chromium-command-line-switches/#use-fake-ui-for-media-stream
settings.CefCommandLineArgs.Add("use-fake-ui-for-media-stream");
//For screen sharing add (see https://bitbucket.org/chromiumembedded/cef/issues/2582/allow-run-time-handling-of-media-access#comment-58677180)
settings.CefCommandLineArgs.Add("enable-usermedia-screen-capturing");

//See https://github.com/cefsharp/CefSharp/wiki/General-Usage#multithreadedmessageloop
//The default is true
const bool multiThreadedMessageLoop = true;

IBrowserProcessHandler browserProcessHandler = null;

if(!multiThreadedMessageLoop)
{
settings.MultiThreadedMessageLoop = false;
browserProcessHandler = new IntegratedMessageLoopBrowserProcessHandler(Dispatcher);
}

// Make sure you set performDependencyCheck false
Cef.Initialize(settings, performDependencyCheck: false, browserProcessHandler: browserProcessHandler);

base.OnStartup(e);
}
}
}
14 changes: 14 additions & 0 deletions CefSharp.Wpf.HwndHost.Example/AssemblyInfo.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// Copyright © 2019 The CefSharp Authors. All rights reserved.
//
// Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.

using System.Windows;

[assembly: ThemeInfo(
ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
//(used if a resource is not found in the page,
// or application resource dictionaries)
ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
//(used if a resource is not found in the page,
// app, or any theme specific resource dictionaries)
)]
34 changes: 34 additions & 0 deletions CefSharp.Wpf.HwndHost.Example/Behaviours/HoverLinkBehaviour.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
using System.Windows;
using System;
using Microsoft.Xaml.Behaviors;

namespace CefSharp.Wpf.HwndHost.Example.Behaviours
{
public class HoverLinkBehaviour : Behavior<ChromiumWebBrowser>
{
// Using a DependencyProperty as the backing store for HoverLink. This enables animation, styling, binding, etc...
public static readonly DependencyProperty HoverLinkProperty = DependencyProperty.Register("HoverLink", typeof(string), typeof(HoverLinkBehaviour), new PropertyMetadata(string.Empty));

public string HoverLink
{
get { return (string)GetValue(HoverLinkProperty); }
set { SetValue(HoverLinkProperty, value); }
}

protected override void OnAttached()
{
AssociatedObject.StatusMessage += OnStatusMessageChanged;
}

protected override void OnDetaching()
{
AssociatedObject.StatusMessage -= OnStatusMessageChanged;
}

private void OnStatusMessageChanged(object sender, StatusMessageEventArgs e)
{
var chromiumWebBrowser = sender as ChromiumWebBrowser;
chromiumWebBrowser.Dispatcher.BeginInvoke((Action)(() => HoverLink = e.Value));
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
using System.Windows.Controls;
using System.Windows.Input;
using Microsoft.Xaml.Behaviors;

namespace CefSharp.Wpf.HwndHost.Example.Behaviours
{
public class TextBoxBindingUpdateOnEnterBehaviour : Behavior<TextBox>
{
protected override void OnAttached()
{
AssociatedObject.KeyDown += OnTextBoxKeyDown;
}

protected override void OnDetaching()
{
AssociatedObject.KeyDown -= OnTextBoxKeyDown;
}

private void OnTextBoxKeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.Enter)
{
var txtBox = sender as TextBox;
txtBox.GetBindingExpression(TextBox.TextProperty).UpdateSource();
}
}
}
}
50 changes: 50 additions & 0 deletions CefSharp.Wpf.HwndHost.Example/CefSharp.Wpf.HwndHost.Example.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net472</TargetFrameworks>
<OutputType>WinExe</OutputType>
<Platforms>x86;x64</Platforms>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<UseWPF>true</UseWPF>
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
<ApplicationManifest>app.manifest</ApplicationManifest>
<StartupObject>CefSharp.Wpf.HwndHost.Example.App</StartupObject>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
<RuntimeIdentifiers>win7-x86;win7-x64</RuntimeIdentifiers>
<LangVersion>9.0</LangVersion>
</PropertyGroup>

<ItemGroup>
<AppDesigner Include="Properties\" />
</ItemGroup>
<ItemGroup>
<None Update="crash_reporter.cfg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\CefSharp.Core.Runtime\CefSharp.Core.Runtime.vcxproj" />
<ProjectReference Include="..\CefSharp.Core\CefSharp.Core.csproj" />
<ProjectReference Include="..\CefSharp.Wpf\CefSharp.Wpf.csproj" />
<ProjectReference Include="..\CefSharp\CefSharp.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="chromiumembeddedframework.runtime" Version="131.3.1" />
<PackageReference Include="MaterialDesignThemes" Version="4.8.0" />
<PackageReference Include="Microsoft.Xaml.Behaviors.Wpf" Version="1.1.39" />
<PackageReference Include="Microsoft.CodeAnalysis.NetAnalyzers" Version="8.0.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>
<Compile Remove="bin.netcore\**" />
<Compile Remove="obj.netcore\**" />
<EmbeddedResource Remove="bin.netcore\**" />
<EmbeddedResource Remove="obj.netcore\**" />
<None Remove="bin.netcore\**" />
<None Remove="obj.netcore\**" />
<Page Remove="bin.netcore\**" />
<Page Remove="obj.netcore\**" />
</ItemGroup>
<Import Project="$(MSBuildThisFileDirectory)..\CefSharp.Native.props" />
</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
<?xml version="1.0" encoding="utf-8"?>
<Project>
<!-- Note: We cannot use the recommended style of specifying <Project Sdk=...> because we need
to set BaseIntermediateOutputPath and BaseOutputPath before the SDK props are imported. -->
<PropertyGroup>
<BaseIntermediateOutputPath>obj.netcore\</BaseIntermediateOutputPath>
<BaseOutputPath>bin.netcore\</BaseOutputPath>
</PropertyGroup>

<Import Project="Sdk.props" Sdk="Microsoft.NET.Sdk.WindowsDesktop" />

<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFrameworks>netcoreapp3.1;net5.0-windows</TargetFrameworks>
<TargetFrameworks Condition="'$(VisualStudioVersion)'=='17.0'">$(TargetFrameworks);net6.0-windows</TargetFrameworks>
<RootNamespace>CefSharp.Wpf.HwndHost.Example</RootNamespace>
<AssemblyName>CefSharp.Wpf.HwndHost.Example</AssemblyName>
<UseWPF>true</UseWPF>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<ApplicationManifest>app.manifest</ApplicationManifest>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<!-- Builds failing for arm64 on appveyor for some reason-->
<!--<Platforms>x86;x64;arm64</Platforms>-->
<Platforms>x86;x64</Platforms>
<!-- Explicitly set the PlatformTarget for arm64, see: https://github.com/dotnet/sdk/issues/15434 -->
<PlatformTarget Condition="'$(Platform)' == 'arm64'">arm64</PlatformTarget>
<StartupObject>CefSharp.Wpf.HwndHost.Example.App</StartupObject>
<!--
Run on a newer version of .Net if the specified version (.Net Core 3.1) is not installed
https://github.com/dotnet/docs/issues/12237
-->
<RollForward>Major</RollForward>
<RuntimeIdentifiers>win-x86;win-x64</RuntimeIdentifiers>
<RuntimeIdentifier Condition="'$(Platform)' == 'x86'">win-x86</RuntimeIdentifier>
<RuntimeIdentifier Condition="'$(Platform)' == 'x64'">win-x64</RuntimeIdentifier>
<RuntimeIdentifier Condition="'$(Platform)' == 'arm64'">win-arm64</RuntimeIdentifier>
<SelfContained Condition="'$(SelfContained)' == ''">false</SelfContained>
<LangVersion>9.0</LangVersion>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\CefSharp.Core\CefSharp.Core.netcore.csproj" />
<ProjectReference Include="..\CefSharp.Wpf\CefSharp.Wpf.netcore.csproj" />
<ProjectReference Include="..\CefSharp\CefSharp.netcore.csproj" />
<PackageReference Include="chromiumembeddedframework.runtime" Version="131.3.1" />
<PackageReference Include="Microsoft.CodeAnalysis.NetAnalyzers" Version="8.0.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="System.Runtime.InteropServices.WindowsRuntime" Version="4.3.0" />
<PackageReference Include="MaterialDesignThemes" Version="4.8.0" />
</ItemGroup>

<ItemGroup>
<None Include="crash_reporter.cfg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>

<ItemGroup>
<!-- Don't include items from the "bin" and "obj" folders used by the .NET Framework projects. -->
<None Remove="bin/**/*.*" />
<None Remove="obj/**/*.*" />
<Compile Remove="obj/**/*.*" />
</ItemGroup>

<Import Project="$(MSBuildThisFileDirectory)..\CefSharp.AfterBuild.targets" />
<Import Project="Sdk.targets" Sdk="Microsoft.NET.Sdk.WindowsDesktop" />
</Project>
Loading