This commit is contained in:
Matthew Leibowitz 2021-04-10 08:54:09 +02:00
Родитель dfc9200364
Коммит ba9b0fd67c
15 изменённых файлов: 279 добавлений и 88 удалений

Просмотреть файл

@ -1,8 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netstandard1.3;netstandard2.0;net462</TargetFrameworks>
<TargetFrameworks Condition="$(BuildingForNet6)">$(TargetFrameworks);net6.0;net6.0-ios10.0;net6.0-maccatalyst13.1;net6.0-tvos10.0;net6.0-macos10.14;net6.0-android</TargetFrameworks>
<TargetFrameworks Condition="$(BuildingForNet6) and $(IsWindows)">$(TargetFrameworks);net6.0-windows7;net6.0-windows10.0.17763</TargetFrameworks>
<TargetFrameworks Condition="$(BuildingForNet6) and !$(SkipBuildingMobile)">$(TargetFrameworks);net6.0;net6.0-ios;net6.0-maccatalyst;net6.0-tvos;net6.0-macos;net6.0-android</TargetFrameworks>
<TargetFrameworks Condition="$(BuildingForNet6) and $(IsWindows)">$(TargetFrameworks);net5.0-windows7;net5.0-windows10.0.17763</TargetFrameworks>
<RootNamespace>SkiaSharp</RootNamespace>
<AssemblyName>SkiaSharp</AssemblyName>
<PackagingGroup>SkiaSharp</PackagingGroup>

Просмотреть файл

@ -7,7 +7,7 @@
IgnorableNamespaces="uap rescap">
<Identity
Name="19f346b4-74d9-47f9-9a56-ba524d74893c"
Name="479d1110-d6ad-48a8-ac62-4af987a884d0"
Publisher="CN=matthew"
Version="1.0.0.0" />
@ -32,7 +32,7 @@
EntryPoint="$targetentrypoint$">
<uap:VisualElements
DisplayName="SkiaSharpSample"
Description="SkiaSharpSample.Package"
Description="SkiaSharpSample"
BackgroundColor="transparent"
Square150x150Logo="Images\Square150x150Logo.png"
Square44x44Logo="Images\Square44x44Logo.png">

Просмотреть файл

@ -36,7 +36,7 @@
</PropertyGroup>
<Import Project="$(WapProjPath)\Microsoft.DesktopBridge.props" />
<PropertyGroup>
<ProjectGuid>8287a10f-d119-4ebf-9cd7-1d697a476d6f</ProjectGuid>
<ProjectGuid>bf0aea36-d579-49ee-a589-705d3d81feb1</ProjectGuid>
<TargetPlatformVersion>10.0.19041.0</TargetPlatformVersion>
<TargetPlatformMinVersion>10.0.17763.0</TargetPlatformMinVersion>
<DefaultLanguage>en-US</DefaultLanguage>

Просмотреть файл

@ -1,51 +1,20 @@
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Controls.Primitives;
using Microsoft.UI.Xaml.Data;
using Microsoft.UI.Xaml.Input;
using Microsoft.UI.Xaml.Media;
using Microsoft.UI.Xaml.Navigation;
using Microsoft.UI.Xaml.Shapes;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.ApplicationModel;
using Windows.ApplicationModel.Activation;
using Windows.Foundation;
using Windows.Foundation.Collections;
// To learn more about WinUI, the WinUI project structure,
// and more about our project templates, see: http://aka.ms/winui-project-info.
namespace SkiaSharpSample
{
/// <summary>
/// Provides application-specific behavior to supplement the default Application class.
/// </summary>
public partial class App : Application
{
/// <summary>
/// Initializes the singleton application object. This is the first line of authored code
/// executed, and as such is the logical equivalent of main() or WinMain().
/// </summary>
private Window window;
public App()
{
this.InitializeComponent();
InitializeComponent();
}
/// <summary>
/// Invoked when the application is launched normally by the end user. Other entry points
/// will be used such as when the application is launched to open a specific file.
/// </summary>
/// <param name="args">Details about the launch request and process.</param>
protected override void OnLaunched(Microsoft.UI.Xaml.LaunchActivatedEventArgs args)
protected override void OnLaunched(LaunchActivatedEventArgs args)
{
m_window = new MainWindow();
m_window.Activate();
window = new MainWindow();
window.Activate();
}
private Window m_window;
}
}

Просмотреть файл

@ -5,9 +5,9 @@
xmlns:local="using:SkiaSharpSample"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:skia="using:SkiaSharp.Views.Windows"
mc:Ignorable="d">
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center">
<Button x:Name="myButton" Click="myButton_Click">Click Me</Button>
</StackPanel>
<skia:SKXamlCanvas PaintSurface="OnPaintSurface" />
</Window>

Просмотреть файл

@ -1,36 +1,42 @@
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Controls.Primitives;
using Microsoft.UI.Xaml.Data;
using Microsoft.UI.Xaml.Input;
using Microsoft.UI.Xaml.Media;
using Microsoft.UI.Xaml.Navigation;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.Foundation;
using Windows.Foundation.Collections;
// To learn more about WinUI, the WinUI project structure,
// and more about our project templates, see: http://aka.ms/winui-project-info.
using SkiaSharp;
using SkiaSharp.Views.Windows;
namespace SkiaSharpSample
{
/// <summary>
/// An empty window that can be used on its own or navigated to within a Frame.
/// </summary>
public sealed partial class MainWindow : Window
{
public MainWindow()
{
this.InitializeComponent();
InitializeComponent();
}
private void myButton_Click(object sender, RoutedEventArgs e)
private void OnPaintSurface(object sender, SKPaintSurfaceEventArgs e)
{
myButton.Content = "Clicked";
// the the canvas and properties
var canvas = e.Surface.Canvas;
// get the screen density for scaling
var scale = (float)((SKXamlCanvas)sender).XamlRoot.RasterizationScale;
var scaledSize = new SKSize(e.Info.Width / scale, e.Info.Height / scale);
// handle the device screen density
canvas.Scale(scale);
// make sure the canvas is blank
canvas.Clear(SKColors.White);
// draw some text
var paint = new SKPaint
{
Color = SKColors.Black,
IsAntialias = true,
Style = SKPaintStyle.Fill,
TextAlign = SKTextAlign.Center,
TextSize = 24
};
var coord = new SKPoint(scaledSize.Width / 2, (scaledSize.Height + paint.TextSize) / 2);
canvas.DrawText("SkiaSharp", coord, paint);
}
}
}

Просмотреть файл

@ -1,7 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net6.0-windows10.0.19041.0</TargetFramework>
<TargetFramework>net5.0-windows10.0.19041.0</TargetFramework>
<TargetPlatformMinVersion>10.0.17763.0</TargetPlatformMinVersion>
<RootNamespace>SkiaSharpSample</RootNamespace>
<ApplicationManifest>app.manifest</ApplicationManifest>
@ -20,4 +21,9 @@
<ProjectReference Include="..\..\..\..\..\binding\SkiaSharp\SkiaSharp.csproj" />
<ProjectReference Include="..\..\..\..\..\source\SkiaSharp.Views\SkiaSharp.Views\SkiaSharp.Views.csproj" />
</ItemGroup>
<ItemGroup>
<Content Include="..\..\..\..\..\output\native\windows\$(Platform)\libSkiaSharp.dll" Condition="Exists('..\..\..\..\..\output\native\windows\$(Platform)\libSkiaSharp.dll')" />
</ItemGroup>
</Project>

Просмотреть файл

@ -0,0 +1,12 @@
<Project>
<!-- workaround for https://github.com/microsoft/ProjectReunion/pull/707 -->
<Target Name="Net6WinUIWorkaround"
BeforeTargets="_GetSdkToolsPathsFromSdk"
Condition="$(TargetFramework.Contains('-windows')) == true ">
<PropertyGroup>
<TargetPlatformIdentifierAdjusted>UAP</TargetPlatformIdentifierAdjusted>
</PropertyGroup>
</Target>
</Project>

Просмотреть файл

@ -14,6 +14,8 @@
<SkiaSharpBuildPropsImported>true</SkiaSharpBuildPropsImported>
<BuildingForNet6>false</BuildingForNet6>
<BuildingForNet6 Condition="$(SolutionFilterName.Contains('-net6')) or $(SolutionFileName.Contains('-net6')) or '$(BuildingInsideVisualStudio)' == 'true'">true</BuildingForNet6>
<SkipBuildingMobile>false</SkipBuildingMobile>
<SkipBuildingMobile Condition="'$(BuildingInsideVisualStudio)' == 'true' and $(SolutionPath.Contains('\WinUI\'))">true</SkipBuildingMobile>
<MDocDocumentationDirectory>$(MSBuildThisFileDirectory)..\docs\SkiaSharpAPI</MDocDocumentationDirectory>
<LangVersion>8.0</LangVersion>
</PropertyGroup>

Просмотреть файл

@ -54,6 +54,7 @@
<PackageReference Include="mdoc" Version="5.7.4.10" PrivateAssets="All" />
</ItemGroup>
<!-- workaround for https://github.com/microsoft/ProjectReunion/pull/707 -->
<Target Name="Net6WinUIWorkaround"
BeforeTargets="_GetSdkToolsPathsFromSdk"
Condition="$(TargetFramework.Contains('-windows')) == true ">

Просмотреть файл

@ -1,11 +1,8 @@
using System;
using System.Runtime.InteropServices;
using Windows.Storage.Streams;
#if WINDOWS
namespace SkiaSharp.Views.Windows
#else
namespace SkiaSharp.Views.UWP
#endif
{
[ComImport]
[Guid("905a0fef-bc53-11df-8c49-001e4fc686da")]
@ -14,4 +11,20 @@ namespace SkiaSharp.Views.UWP
{
long Buffer([Out] out IntPtr value);
}
internal static class Utils
{
internal static IntPtr GetByteBuffer(this IBuffer buffer)
{
var byteBuffer = buffer as IBufferByteAccess;
if (byteBuffer == null)
throw new InvalidCastException("Unable to convert WriteableBitmap.PixelBuffer to IBufferByteAccess.");
var hr = byteBuffer.Buffer(out var ptr);
if (hr < 0)
throw new InvalidCastException("Unable to retrieve pixel address from WriteableBitmap.PixelBuffer.");
return ptr;
}
}
}

Просмотреть файл

@ -100,6 +100,7 @@ namespace SkiaSharp.Views.UWP
{
var root = xamlRoot ?? XamlRoot;
Dpi = root.RasterizationScale;
Invalidate();
}
#else
private void OnDpiChanged(DisplayInformation sender, object args = null)

Просмотреть файл

@ -169,19 +169,8 @@ namespace SkiaSharp.Views.UWP
}
}
internal static IntPtr GetPixels(this WriteableBitmap bitmap)
{
var buffer = bitmap.PixelBuffer as IBufferByteAccess;
if (buffer == null)
throw new InvalidCastException("Unable to convert WriteableBitmap.PixelBuffer to IBufferByteAccess.");
IntPtr ptr;
var hr = buffer.Buffer(out ptr);
if (hr < 0)
throw new InvalidCastException("Unable to retrieve pixel address from WriteableBitmap.PixelBuffer.");
return ptr;
}
internal static IntPtr GetPixels(this WriteableBitmap bitmap) =>
bitmap.PixelBuffer.GetByteBuffer();
#endif
}
}

Просмотреть файл

@ -0,0 +1,101 @@
using System;
using System.Runtime.InteropServices;
using Windows.Storage.Streams;
using WinRT;
using WinRT.Interop;
namespace SkiaSharp.Views.Windows
{
[WindowsRuntimeType("Windows.Foundation.UniversalApiContract")]
[Guid("905a0fef-bc53-11df-8c49-001e4fc686da")]
internal interface IBufferByteAccess
{
IntPtr Buffer { get; }
}
internal static class Utils
{
internal static IntPtr GetByteBuffer(this IBuffer buffer)
{
var byteBuffer = buffer.As<IBufferByteAccess>();
if (byteBuffer == null)
throw new InvalidCastException("Unable to convert WriteableBitmap.PixelBuffer to IBufferByteAccess.");
return byteBuffer.Buffer;
}
}
}
namespace ABI.SkiaSharp.Views.Windows
{
[DynamicInterfaceCastableImplementation]
[Guid("905a0fef-bc53-11df-8c49-001e4fc686da")]
internal interface IBufferByteAccess : global::SkiaSharp.Views.Windows.IBufferByteAccess
{
public struct VftblPtr
{
public IntPtr Vftbl;
}
[Guid("905a0fef-bc53-11df-8c49-001e4fc686da")]
public struct Vftbl
{
public delegate int GetBufferDelegate(IntPtr thisPtr, out IntPtr buffer);
internal IUnknownVftbl IUnknownVftbl;
public GetBufferDelegate getBuffer;
static unsafe Vftbl()
{
AbiToProjectionVftable = new Vftbl
{
IUnknownVftbl = IUnknownVftbl.AbiToProjectionVftbl,
getBuffer = DoAbiGetBuffer
};
var nativeVftbl = (IntPtr*)Marshal.AllocCoTaskMem(Marshal.SizeOf<IUnknownVftbl>() + sizeof(IntPtr) * 12);
Marshal.StructureToPtr(AbiToProjectionVftable.IUnknownVftbl, (IntPtr)nativeVftbl, false);
nativeVftbl[3] = Marshal.GetFunctionPointerForDelegate(AbiToProjectionVftable.getBuffer);
AbiToProjectionVftablePtr = (IntPtr)nativeVftbl;
}
public static readonly Vftbl AbiToProjectionVftable;
public static readonly IntPtr AbiToProjectionVftablePtr;
internal unsafe Vftbl(IntPtr ptr)
{
var vftblPtr = Marshal.PtrToStructure<VftblPtr>(ptr);
var vftbl = (IntPtr*)vftblPtr.Vftbl;
IUnknownVftbl = Marshal.PtrToStructure<IUnknownVftbl>(vftblPtr.Vftbl);
getBuffer = Marshal.GetDelegateForFunctionPointer<GetBufferDelegate>(vftbl[3]);
}
private static int DoAbiGetBuffer(IntPtr thisPtr, out IntPtr buffer)
{
buffer = default;
try
{
buffer = ComWrappersSupport.FindObject<global::SkiaSharp.Views.Windows.IBufferByteAccess>(thisPtr).Buffer;
}
catch (Exception ex)
{
return Marshal.GetHRForException(ex);
}
return 0;
}
}
IntPtr global::SkiaSharp.Views.Windows.IBufferByteAccess.Buffer
{
get
{
var obj = (ObjectReference<Vftbl>)((IWinRTObject)this).GetObjectReferenceForType(typeof(global::SkiaSharp.Views.Windows.IBufferByteAccess).TypeHandle);
var ThisPtr = obj.ThisPtr;
Marshal.ThrowExceptionForHR(obj.Vftbl.getBuffer(ThisPtr, out IntPtr buffer));
return buffer;
}
}
internal static ObjectReference<Vftbl> FromAbi(IntPtr thisPtr) =>
ObjectReference<Vftbl>.FromAbi(thisPtr);
}
}

Просмотреть файл

@ -1,8 +1,99 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net6.0-ios</TargetFrameworks>
<!--<TargetFrameworks>net6.0-ios10.0;net6.0-maccatalyst13.1;net6.0-tvos10.0;net6.0-macos10.14;net6.0-android</TargetFrameworks>-->
<!--<TargetFrameworks Condition="$(IsWindows)">$(TargetFrameworks);net6.0-windows10.0.18362</TargetFrameworks>-->
<TargetFrameworks Condition="$(BuildingForNet6) and !$(SkipBuildingMobile)">$(TargetFrameworks);net6.0;net6.0-ios;net6.0-maccatalyst;net6.0-tvos;net6.0-macos;net6.0-android</TargetFrameworks>
<TargetFrameworks Condition="$(BuildingForNet6) and $(IsWindows)">$(TargetFrameworks);net5.0-windows10.0.18362</TargetFrameworks>
<PackagingGroup>SkiaSharp.Views</PackagingGroup>
</PropertyGroup>
<PropertyGroup Condition="$(TargetFramework.Contains('-ios')) or $(TargetFramework.Contains('-maccatalyst'))">
<RootNamespace>SkiaSharp.Views.iOS</RootNamespace>
<AssemblyName>SkiaSharp.Views.iOS</AssemblyName>
</PropertyGroup>
<PropertyGroup Condition="$(TargetFramework.Contains('-tvos'))">
<RootNamespace>SkiaSharp.Views.tvOS</RootNamespace>
<AssemblyName>SkiaSharp.Views.tvOS</AssemblyName>
</PropertyGroup>
<PropertyGroup Condition="$(TargetFramework.Contains('-watchos'))">
<RootNamespace>SkiaSharp.Views.watchOS</RootNamespace>
<AssemblyName>SkiaSharp.Views.watchOS</AssemblyName>
</PropertyGroup>
<PropertyGroup Condition="$(TargetFramework.Contains('-macos'))">
<RootNamespace>SkiaSharp.Views.Mac</RootNamespace>
<AssemblyName>SkiaSharp.Views.Mac</AssemblyName>
</PropertyGroup>
<PropertyGroup Condition="$(TargetFramework.Contains('-android'))">
<RootNamespace>SkiaSharp.Views.Android</RootNamespace>
<AssemblyName>SkiaSharp.Views.Android</AssemblyName>
</PropertyGroup>
<PropertyGroup Condition="$(TargetFramework.Contains('-windows'))">
<TargetPlatformMinVersion>10.0.17763.0</TargetPlatformMinVersion>
<RootNamespace>SkiaSharp.Views.Windows</RootNamespace>
<AssemblyName>SkiaSharp.Views.Windows</AssemblyName>
</PropertyGroup>
<ItemGroup Condition="$(TargetFramework.Contains('-windows'))">
<PackageReference Include="Microsoft.ProjectReunion" Version="0.5.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\binding\SkiaSharp\SkiaSharp.csproj" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\SkiaSharp.Views.Shared\**\*.cs" Link="%(RecursiveDir)%(Filename)%(Extension)" />
</ItemGroup>
<ItemGroup>
<!-- iOS / Mac Catalyst -->
<None Include="..\SkiaSharp.Views.Apple\**\*.cs" Link="Platform\iOS\%(RecursiveDir)%(Filename)%(Extension)" />
<None Include="..\SkiaSharp.Views.AppleiOS\**\*.cs" Link="Platform\iOS\%(RecursiveDir)%(Filename)%(Extension)" />
<None Include="..\SkiaSharp.Views.iOS\**\*.cs" Link="Platform\iOS\%(RecursiveDir)%(Filename)%(Extension)" />
<!-- tvOS -->
<None Include="..\SkiaSharp.Views.Apple\**\*.cs" Link="Platform\tvOS\%(RecursiveDir)%(Filename)%(Extension)" />
<None Include="..\SkiaSharp.Views.AppleiOS\**\*.cs" Link="Platform\tvOS\%(RecursiveDir)%(Filename)%(Extension)" />
<None Include="..\SkiaSharp.Views.tvOS\**\*.cs" Link="Platform\tvOS\%(RecursiveDir)%(Filename)%(Extension)" />
<!-- watchOS -->
<None Include="..\SkiaSharp.Views.Apple\**\*.cs" Link="Platform\watchOS\%(RecursiveDir)%(Filename)%(Extension)" />
<None Include="..\SkiaSharp.Views.AppleiOS\**\*.cs" Link="Platform\watchOS\%(RecursiveDir)%(Filename)%(Extension)" />
<None Include="..\SkiaSharp.Views.watchOS\**\*.cs" Link="Platform\watchOS\%(RecursiveDir)%(Filename)%(Extension)" />
<!-- macOS -->
<None Include="..\SkiaSharp.Views.Apple\**\*.cs" Link="Platform\macOS\%(RecursiveDir)%(Filename)%(Extension)" />
<None Include="..\SkiaSharp.Views.Mac\**\*.cs" Link="Platform\macOS\%(RecursiveDir)%(Filename)%(Extension)" />
<!-- Android -->
<None Include="..\SkiaSharp.Views.Android\**\*.cs" Link="Platform\Android\%(RecursiveDir)%(Filename)%(Extension)" />
<!-- Windows -->
<None Include="..\SkiaSharp.Views.UWP\**\*.cs" Link="Platform\Windows\%(RecursiveDir)%(Filename)%(Extension)" />
<None Remove="..\SkiaSharp.Views.UWP\Interop\IBufferByteAccess.cs" />
</ItemGroup>
<ItemGroup Condition="$(TargetFramework.Contains('-ios')) or $(TargetFramework.Contains('-maccatalyst'))">
<!-- iOS / Mac Catalyst -->
<Compile Include="..\SkiaSharp.Views.Apple\**\*.cs" Link="Platform\iOS\%(RecursiveDir)%(Filename)%(Extension)" />
<Compile Include="..\SkiaSharp.Views.AppleiOS\**\*.cs" Link="Platform\iOS\%(RecursiveDir)%(Filename)%(Extension)" />
<Compile Include="..\SkiaSharp.Views.iOS\**\*.cs" Link="Platform\iOS\%(RecursiveDir)%(Filename)%(Extension)" />
</ItemGroup>
<ItemGroup Condition="$(TargetFramework.Contains('-tvos'))">
<!-- tvOS -->
<Compile Include="..\SkiaSharp.Views.Apple\**\*.cs" Link="Platform\tvOS\%(RecursiveDir)%(Filename)%(Extension)" />
<Compile Include="..\SkiaSharp.Views.AppleiOS\**\*.cs" Link="Platform\tvOS\%(RecursiveDir)%(Filename)%(Extension)" />
<Compile Include="..\SkiaSharp.Views.tvOS\**\*.cs" Link="Platform\tvOS\%(RecursiveDir)%(Filename)%(Extension)" />
</ItemGroup>
<ItemGroup Condition="$(TargetFramework.Contains('-watchos'))">
<!-- watchOS -->
<Compile Include="..\SkiaSharp.Views.Apple\**\*.cs" Link="Platform\watchOS\%(RecursiveDir)%(Filename)%(Extension)" />
<Compile Include="..\SkiaSharp.Views.AppleiOS\**\*.cs" Link="Platform\watchOS\%(RecursiveDir)%(Filename)%(Extension)" />
<Compile Include="..\SkiaSharp.Views.watchOS\**\*.cs" Link="Platform\watchOS\%(RecursiveDir)%(Filename)%(Extension)" />
</ItemGroup>
<ItemGroup Condition="$(TargetFramework.Contains('-macos'))">
<!-- macOS -->
<Compile Include="..\SkiaSharp.Views.Apple\**\*.cs" Link="Platform\macOS\%(RecursiveDir)%(Filename)%(Extension)" />
<Compile Include="..\SkiaSharp.Views.Mac\**\*.cs" Link="Platform\macOS\%(RecursiveDir)%(Filename)%(Extension)" />
</ItemGroup>
<ItemGroup Condition="$(TargetFramework.Contains('-android'))">
<!-- Android -->
<Compile Include="..\SkiaSharp.Views.Android\**\*.cs" Link="Platform\Android\%(RecursiveDir)%(Filename)%(Extension)" />
</ItemGroup>
<ItemGroup Condition="$(TargetFramework.Contains('-windows'))">
<!-- Windows -->
<Compile Include="..\SkiaSharp.Views.UWP\**\*.cs" Link="Platform\Windows\%(RecursiveDir)%(Filename)%(Extension)" />
<Compile Remove="..\SkiaSharp.Views.UWP\Interop\IBufferByteAccess.cs" />
</ItemGroup>
<ItemGroup>
<Compile Remove="..\*\bin\**;..\*\obj\**" />
<None Remove="..\*\bin\**;..\*\obj\**" />
</ItemGroup>
</Project>