Browse Source

Merge branch 'master' into screen-updates

pull/9133/head
robloo 4 years ago
committed by GitHub
parent
commit
2a12130fd8
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 6
      .editorconfig
  2. 49
      src/Avalonia.Base/Media/Color.cs
  3. 30
      src/Avalonia.Base/Media/HslColor.cs
  4. 30
      src/Avalonia.Base/Media/HsvColor.cs
  5. 49
      src/Avalonia.Base/Utilities/SpanHelpers.cs
  6. 72
      src/Avalonia.Build.Tasks/SpanCompat.cs
  7. 4
      src/Avalonia.Controls.DataGrid/DataGridValueConverter.cs
  8. 4
      src/Avalonia.Controls/AppBuilderBase.cs
  9. 2
      src/Avalonia.Controls/DateTimePickers/TimePicker.cs
  10. 2
      src/Avalonia.Controls/DefinitionBase.cs
  11. 2
      src/Avalonia.DesignerSupport/Remote/HtmlTransport/SimpleWebSocketHttpServer.cs
  12. 1
      src/Avalonia.MicroCom/Avalonia.MicroCom.csproj
  13. 4
      src/Avalonia.MicroCom/CallbackBase.cs
  14. 9
      src/Avalonia.MicroCom/IMicroComExceptionCallback.cs
  15. 9
      src/Avalonia.MicroCom/IMicroComShadowContainer.cs
  16. 8
      src/Avalonia.MicroCom/IUnknown.cs
  17. 17
      src/Avalonia.MicroCom/LocalInterop.cs
  18. 110
      src/Avalonia.MicroCom/MicroComProxyBase.cs
  19. 143
      src/Avalonia.MicroCom/MicroComRuntime.cs
  20. 177
      src/Avalonia.MicroCom/MicroComShadow.cs
  21. 47
      src/Avalonia.MicroCom/MicroComVtblBase.cs
  22. 1
      src/Avalonia.Native/Avalonia.Native.csproj
  23. 1
      src/Avalonia.Native/AvaloniaNativePlatform.cs
  24. 1
      src/Avalonia.Native/CallbackBase.cs
  25. 1
      src/Avalonia.Native/NativeControlHostImpl.cs
  26. 2
      src/Avalonia.X11/X11Structs.cs
  27. 18
      src/Markup/Avalonia.Markup/Markup/Parsers/SelectorGrammar.cs
  28. 1
      src/Windows/Avalonia.Win32/Avalonia.Win32.csproj
  29. 7
      src/Windows/Avalonia.Win32/ClipboardImpl.cs
  30. 5
      src/Windows/Avalonia.Win32/DragSource.cs
  31. 1
      src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs
  32. 3
      src/Windows/Avalonia.Win32/OleContext.cs
  33. 2
      src/Windows/Avalonia.Win32/OleDataObject.cs
  34. 1
      src/Windows/Avalonia.Win32/OleDropTarget.cs
  35. 1
      src/Windows/Avalonia.Win32/Win32StorageProvider.cs
  36. 1
      src/Windows/Avalonia.Win32/WinRT/Composition/WinUICompositedWindow.cs
  37. 1
      src/Windows/Avalonia.Win32/WinRT/Composition/WinUICompositorConnection.cs
  38. 1
      src/Windows/Avalonia.Win32/WinRT/Composition/WinUIEffectBase.cs
  39. 1
      src/Windows/Avalonia.Win32/WinRT/Composition/WinUiCompositedWindowSurface.cs
  40. 1
      src/Windows/Avalonia.Win32/WinRT/NativeWinRTMethods.cs
  41. 1
      src/Windows/Avalonia.Win32/WinRT/WinRTInspectable.cs
  42. 2
      tests/Avalonia.Base.UnitTests/Media/TextFormatting/GraphemeBreakTestDataGenerator.cs
  43. 1
      tests/Avalonia.Benchmarks/Avalonia.Benchmarks.csproj

6
.editorconfig

@ -139,10 +139,12 @@ dotnet_analyzer_diagnostic.category-Performance.severity = none #error - Uncomme
# CA1802: Use literals where appropriate # CA1802: Use literals where appropriate
dotnet_diagnostic.CA1802.severity = warning dotnet_diagnostic.CA1802.severity = warning
# CA1825: Avoid zero-length array allocations # CA1820: Test for empty strings using string length
dotnet_diagnostic.CA1825.severity = warning dotnet_diagnostic.CA1820.severity = warning
# CA1821: Remove empty finalizers # CA1821: Remove empty finalizers
dotnet_diagnostic.CA1821.severity = warning dotnet_diagnostic.CA1821.severity = warning
# CA1825: Avoid zero-length array allocations
dotnet_diagnostic.CA1825.severity = warning
#CA1847: Use string.Contains(char) instead of string.Contains(string) with single characters #CA1847: Use string.Contains(char) instead of string.Contains(string) with single characters
dotnet_diagnostic.CA1847.severity = warning dotnet_diagnostic.CA1847.severity = warning

49
src/Avalonia.Base/Media/Color.cs

@ -9,6 +9,7 @@ using System;
using System.Globalization; using System.Globalization;
#if !BUILDTASK #if !BUILDTASK
using Avalonia.Animation.Animators; using Avalonia.Animation.Animators;
using static Avalonia.Utilities.SpanHelpers;
#endif #endif
namespace Avalonia.Media namespace Avalonia.Media
@ -295,9 +296,7 @@ namespace Avalonia.Media
return false; return false;
} }
// TODO: (netstandard 2.1) Can use allocation free parsing. if (!input.TryParseUInt(NumberStyles.HexNumber, CultureInfo.InvariantCulture, out var parsed))
if (!uint.TryParse(input.ToString(), NumberStyles.HexNumber, CultureInfo.InvariantCulture,
out var parsed))
{ {
return false; return false;
} }
@ -382,9 +381,9 @@ namespace Avalonia.Media
if (components.Length == 3) // RGB if (components.Length == 3) // RGB
{ {
if (InternalTryParseByte(components[0], out byte red) && if (InternalTryParseByte(components[0].AsSpan(), out byte red) &&
InternalTryParseByte(components[1], out byte green) && InternalTryParseByte(components[1].AsSpan(), out byte green) &&
InternalTryParseByte(components[2], out byte blue)) InternalTryParseByte(components[2].AsSpan(), out byte blue))
{ {
color = new Color(0xFF, red, green, blue); color = new Color(0xFF, red, green, blue);
return true; return true;
@ -392,10 +391,10 @@ namespace Avalonia.Media
} }
else if (components.Length == 4) // RGBA else if (components.Length == 4) // RGBA
{ {
if (InternalTryParseByte(components[0], out byte red) && if (InternalTryParseByte(components[0].AsSpan(), out byte red) &&
InternalTryParseByte(components[1], out byte green) && InternalTryParseByte(components[1].AsSpan(), out byte green) &&
InternalTryParseByte(components[2], out byte blue) && InternalTryParseByte(components[2].AsSpan(), out byte blue) &&
InternalTryParseDouble(components[3], out double alpha)) InternalTryParseDouble(components[3].AsSpan(), out double alpha))
{ {
color = new Color((byte)Math.Round(alpha * 255.0), red, green, blue); color = new Color((byte)Math.Round(alpha * 255.0), red, green, blue);
return true; return true;
@ -403,17 +402,14 @@ namespace Avalonia.Media
} }
// Local function to specially parse a byte value with an optional percentage sign // Local function to specially parse a byte value with an optional percentage sign
bool InternalTryParseByte(string inString, out byte outByte) bool InternalTryParseByte(ReadOnlySpan<char> inString, out byte outByte)
{ {
// The percent sign, if it exists, must be at the end of the number // The percent sign, if it exists, must be at the end of the number
int percentIndex = inString.IndexOf("%", StringComparison.Ordinal); int percentIndex = inString.IndexOf("%".AsSpan(), StringComparison.Ordinal);
if (percentIndex >= 0) if (percentIndex >= 0)
{ {
var result = double.TryParse( var result = inString.Slice(0, percentIndex).TryParseDouble(NumberStyles.Number, CultureInfo.InvariantCulture,
inString.Substring(0, percentIndex),
NumberStyles.Number,
CultureInfo.InvariantCulture,
out double percentage); out double percentage);
outByte = (byte)Math.Round((percentage / 100.0) * 255.0); outByte = (byte)Math.Round((percentage / 100.0) * 255.0);
@ -421,37 +417,28 @@ namespace Avalonia.Media
} }
else else
{ {
return byte.TryParse( return inString.TryParseByte(NumberStyles.Number, CultureInfo.InvariantCulture,
inString,
NumberStyles.Number,
CultureInfo.InvariantCulture,
out outByte); out outByte);
} }
} }
// Local function to specially parse a double value with an optional percentage sign // Local function to specially parse a double value with an optional percentage sign
bool InternalTryParseDouble(string inString, out double outDouble) bool InternalTryParseDouble(ReadOnlySpan<char> inString, out double outDouble)
{ {
// The percent sign, if it exists, must be at the end of the number // The percent sign, if it exists, must be at the end of the number
int percentIndex = inString.IndexOf("%", StringComparison.Ordinal); int percentIndex = inString.IndexOf("%".AsSpan(), StringComparison.Ordinal);
if (percentIndex >= 0) if (percentIndex >= 0)
{ {
var result = double.TryParse( var result = inString.Slice(0, percentIndex).TryParseDouble(NumberStyles.Number, CultureInfo.InvariantCulture,
inString.Substring(0, percentIndex), out double percentage);
NumberStyles.Number,
CultureInfo.InvariantCulture,
out double percentage);
outDouble = percentage / 100.0; outDouble = percentage / 100.0;
return result; return result;
} }
else else
{ {
return double.TryParse( return inString.TryParseDouble(NumberStyles.Number, CultureInfo.InvariantCulture,
inString,
NumberStyles.Number,
CultureInfo.InvariantCulture,
out outDouble); out outDouble);
} }
} }

30
src/Avalonia.Base/Media/HslColor.cs

@ -302,9 +302,9 @@ namespace Avalonia.Media
if (components.Length == 3) // HSL if (components.Length == 3) // HSL
{ {
if (double.TryParse(components[0], NumberStyles.Number, CultureInfo.InvariantCulture, out double hue) && if (components[0].AsSpan().TryParseDouble(NumberStyles.Number, CultureInfo.InvariantCulture, out double hue) &&
TryInternalParse(components[1], out double saturation) && TryInternalParse(components[1].AsSpan(), out double saturation) &&
TryInternalParse(components[2], out double lightness)) TryInternalParse(components[2].AsSpan(), out double lightness))
{ {
hslColor = new HslColor(1.0, hue, saturation, lightness); hslColor = new HslColor(1.0, hue, saturation, lightness);
return true; return true;
@ -312,10 +312,10 @@ namespace Avalonia.Media
} }
else if (components.Length == 4) // HSLA else if (components.Length == 4) // HSLA
{ {
if (double.TryParse(components[0], NumberStyles.Number, CultureInfo.InvariantCulture, out double hue) && if (components[0].AsSpan().TryParseDouble(NumberStyles.Number, CultureInfo.InvariantCulture, out double hue) &&
TryInternalParse(components[1], out double saturation) && TryInternalParse(components[1].AsSpan(), out double saturation) &&
TryInternalParse(components[2], out double lightness) && TryInternalParse(components[2].AsSpan(), out double lightness) &&
TryInternalParse(components[3], out double alpha)) TryInternalParse(components[3].AsSpan(), out double alpha))
{ {
hslColor = new HslColor(alpha, hue, saturation, lightness); hslColor = new HslColor(alpha, hue, saturation, lightness);
return true; return true;
@ -323,28 +323,22 @@ namespace Avalonia.Media
} }
// Local function to specially parse a double value with an optional percentage sign // Local function to specially parse a double value with an optional percentage sign
bool TryInternalParse(string inString, out double outDouble) bool TryInternalParse(ReadOnlySpan<char> inString, out double outDouble)
{ {
// The percent sign, if it exists, must be at the end of the number // The percent sign, if it exists, must be at the end of the number
int percentIndex = inString.IndexOf("%", StringComparison.Ordinal); int percentIndex = inString.IndexOf("%".AsSpan(), StringComparison.Ordinal);
if (percentIndex >= 0) if (percentIndex >= 0)
{ {
var result = double.TryParse( var result = inString.Slice(0, percentIndex).TryParseDouble(NumberStyles.Number, CultureInfo.InvariantCulture,
inString.Substring(0, percentIndex), out double percentage);
NumberStyles.Number,
CultureInfo.InvariantCulture,
out double percentage);
outDouble = percentage / 100.0; outDouble = percentage / 100.0;
return result; return result;
} }
else else
{ {
return double.TryParse( return inString.TryParseDouble(NumberStyles.Number, CultureInfo.InvariantCulture,
inString,
NumberStyles.Number,
CultureInfo.InvariantCulture,
out outDouble); out outDouble);
} }
} }

30
src/Avalonia.Base/Media/HsvColor.cs

@ -302,9 +302,9 @@ namespace Avalonia.Media
if (components.Length == 3) // HSV if (components.Length == 3) // HSV
{ {
if (double.TryParse(components[0], NumberStyles.Number, CultureInfo.InvariantCulture, out double hue) && if (components[0].AsSpan().TryParseDouble(NumberStyles.Number, CultureInfo.InvariantCulture, out double hue) &&
TryInternalParse(components[1], out double saturation) && TryInternalParse(components[1].AsSpan(), out double saturation) &&
TryInternalParse(components[2], out double value)) TryInternalParse(components[2].AsSpan(), out double value))
{ {
hsvColor = new HsvColor(1.0, hue, saturation, value); hsvColor = new HsvColor(1.0, hue, saturation, value);
return true; return true;
@ -312,10 +312,10 @@ namespace Avalonia.Media
} }
else if (components.Length == 4) // HSVA else if (components.Length == 4) // HSVA
{ {
if (double.TryParse(components[0], NumberStyles.Number, CultureInfo.InvariantCulture, out double hue) && if (components[0].AsSpan().TryParseDouble(NumberStyles.Number, CultureInfo.InvariantCulture, out double hue) &&
TryInternalParse(components[1], out double saturation) && TryInternalParse(components[1].AsSpan(), out double saturation) &&
TryInternalParse(components[2], out double value) && TryInternalParse(components[2].AsSpan(), out double value) &&
TryInternalParse(components[3], out double alpha)) TryInternalParse(components[3].AsSpan(), out double alpha))
{ {
hsvColor = new HsvColor(alpha, hue, saturation, value); hsvColor = new HsvColor(alpha, hue, saturation, value);
return true; return true;
@ -323,28 +323,22 @@ namespace Avalonia.Media
} }
// Local function to specially parse a double value with an optional percentage sign // Local function to specially parse a double value with an optional percentage sign
bool TryInternalParse(string inString, out double outDouble) bool TryInternalParse(ReadOnlySpan<char> inString, out double outDouble)
{ {
// The percent sign, if it exists, must be at the end of the number // The percent sign, if it exists, must be at the end of the number
int percentIndex = inString.IndexOf("%", StringComparison.Ordinal); int percentIndex = inString.IndexOf("%".AsSpan(), StringComparison.Ordinal);
if (percentIndex >= 0) if (percentIndex >= 0)
{ {
var result = double.TryParse( var result = inString.Slice(0, percentIndex).TryParseDouble(NumberStyles.Number, CultureInfo.InvariantCulture,
inString.Substring(0, percentIndex), out double percentage);
NumberStyles.Number,
CultureInfo.InvariantCulture,
out double percentage);
outDouble = percentage / 100.0; outDouble = percentage / 100.0;
return result; return result;
} }
else else
{ {
return double.TryParse( return inString.TryParseDouble(NumberStyles.Number, CultureInfo.InvariantCulture,
inString,
NumberStyles.Number,
CultureInfo.InvariantCulture,
out outDouble); out outDouble);
} }
} }

49
src/Avalonia.Base/Utilities/SpanHelpers.cs

@ -0,0 +1,49 @@
using System;
using System.Globalization;
using System.Runtime.CompilerServices;
namespace Avalonia.Utilities
{
public static class SpanHelpers
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool TryParseUInt(this ReadOnlySpan<char> span, NumberStyles style, IFormatProvider provider, out uint value)
{
#if NETSTANDARD2_0
return uint.TryParse(span.ToString(), style, provider, out value);
#else
return uint.TryParse(span, style, provider, out value);
#endif
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool TryParseInt(this ReadOnlySpan<char> span, out int value)
{
#if NETSTANDARD2_0
return int.TryParse(span.ToString(), out value);
#else
return int.TryParse(span, out value);
#endif
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool TryParseDouble(this ReadOnlySpan<char> span, NumberStyles style, IFormatProvider provider, out double value)
{
#if NETSTANDARD2_0
return double.TryParse(span.ToString(), style, provider, out value);
#else
return double.TryParse(span, style, provider, out value);
#endif
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool TryParseByte(this ReadOnlySpan<char> span, NumberStyles style, IFormatProvider provider, out byte value)
{
#if NETSTANDARD2_0
return byte.TryParse(span.ToString(), style, provider, out value);
#else
return byte.TryParse(span, style, provider, out value);
#endif
}
}
}

72
src/Avalonia.Build.Tasks/SpanCompat.cs

@ -1,4 +1,7 @@
#if !NETCOREAPP3_1_OR_GREATER #if !NETCOREAPP3_1_OR_GREATER
using System.Globalization;
using System.Runtime.CompilerServices;
namespace System namespace System
{ {
// This is a hack to enable our span code to work inside MSBuild task without referencing System.Memory // This is a hack to enable our span code to work inside MSBuild task without referencing System.Memory
@ -9,6 +12,8 @@ namespace System
private int _length; private int _length;
public int Length => _length; public int Length => _length;
public static implicit operator ReadOnlySpan<T>(string s) => new ReadOnlySpan<T>(s);
public ReadOnlySpan(string s) : this(s, 0, s.Length) public ReadOnlySpan(string s) : this(s, 0, s.Length)
{ {
@ -63,8 +68,75 @@ namespace System
return Slice(start); return Slice(start);
} }
public ReadOnlySpan<char> TrimEnd()
{
int end = Length - 1;
for (; end >= 0; end--)
{
if (!char.IsWhiteSpace(this[end]))
{
break;
}
}
return Slice(0, end + 1);
}
public ReadOnlySpan<char> Trim()
{
return TrimStart().TrimEnd();
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool TryParseUInt(NumberStyles style, IFormatProvider provider, out uint value)
{
return uint.TryParse(ToString(), style, provider, out value);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool TryParseInt(out int value)
{
return int.TryParse(ToString(), out value);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool TryParseDouble(NumberStyles style, IFormatProvider provider, out double value)
{
return double.TryParse(ToString(), style, provider, out value);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool TryParseByte(NumberStyles style, IFormatProvider provider, out byte value)
{
return byte.TryParse(ToString(), style, provider, out value);
}
public override string ToString() => _length == 0 ? string.Empty : _s.Substring(_start, _length); public override string ToString() => _length == 0 ? string.Empty : _s.Substring(_start, _length);
internal int IndexOf(ReadOnlySpan<char> v, StringComparison ordinal, int start = 0)
{
if(Length == 0 || v.IsEmpty)
{
return -1;
}
for (var c = start; c < _length; c++)
{
if (this[c] == v[0])
{
for(var i = 0; i < v.Length; i++)
{
if (this[c + i] != v[i])
{
break;
}
}
return c;
}
}
return -1;
}
public static implicit operator ReadOnlySpan<T>(char[] arr) => new ReadOnlySpan<T>(new string(arr)); public static implicit operator ReadOnlySpan<T>(char[] arr) => new ReadOnlySpan<T>(new string(arr));
} }

4
src/Avalonia.Controls.DataGrid/DataGridValueConverter.cs

@ -28,8 +28,8 @@ namespace Avalonia.Controls
{ {
if (targetType != null && targetType.IsNullableType()) if (targetType != null && targetType.IsNullableType())
{ {
String strValue = value as String; var strValue = value as string;
if (strValue == String.Empty) if (string.IsNullOrEmpty(strValue))
{ {
return null; return null;
} }

4
src/Avalonia.Controls/AppBuilderBase.cs

@ -210,9 +210,9 @@ namespace Avalonia.Controls
{ {
var moduleInitializers = from assembly in AppDomain.CurrentDomain.GetAssemblies() var moduleInitializers = from assembly in AppDomain.CurrentDomain.GetAssemblies()
from attribute in assembly.GetCustomAttributes<ExportAvaloniaModuleAttribute>() from attribute in assembly.GetCustomAttributes<ExportAvaloniaModuleAttribute>()
where attribute.ForWindowingSubsystem == "" where string.IsNullOrEmpty(attribute.ForWindowingSubsystem)
|| attribute.ForWindowingSubsystem == WindowingSubsystemName || attribute.ForWindowingSubsystem == WindowingSubsystemName
where attribute.ForRenderingSubsystem == "" where string.IsNullOrEmpty(attribute.ForRenderingSubsystem)
|| attribute.ForRenderingSubsystem == RenderingSubsystemName || attribute.ForRenderingSubsystem == RenderingSubsystemName
group attribute by attribute.Name into exports group attribute by attribute.Name into exports
select (from export in exports select (from export in exports

2
src/Avalonia.Controls/DateTimePickers/TimePicker.cs

@ -99,7 +99,7 @@ namespace Avalonia.Controls
get => _clockIdentifier; get => _clockIdentifier;
set set
{ {
if (!(string.IsNullOrEmpty(value) || value == "" || value == "12HourClock" || value == "24HourClock")) if (!(string.IsNullOrEmpty(value) || value == "12HourClock" || value == "24HourClock"))
throw new ArgumentException("Invalid ClockIdentifier"); throw new ArgumentException("Invalid ClockIdentifier");
SetAndRaise(ClockIdentifierProperty, ref _clockIdentifier, value); SetAndRaise(ClockIdentifierProperty, ref _clockIdentifier, value);
SetGrid(); SetGrid();

2
src/Avalonia.Controls/DefinitionBase.cs

@ -366,7 +366,7 @@ namespace Avalonia.Controls
string id = (string)value; string id = (string)value;
if (id != string.Empty) if (!string.IsNullOrEmpty(id))
{ {
int i = -1; int i = -1;
while (++i < id.Length) while (++i < id.Length)

2
src/Avalonia.DesignerSupport/Remote/HtmlTransport/SimpleWebSocketHttpServer.cs

@ -72,7 +72,7 @@ namespace Avalonia.DesignerSupport.Remote.HtmlTransport
while (true) while (true)
{ {
line = await ReadLineAsync(); line = await ReadLineAsync();
if (line == "") if (string.IsNullOrEmpty(line))
break; break;
sp = line.Split(new[] {':'}, 2); sp = line.Split(new[] {':'}, 2);
headers[sp[0]] = sp[1].TrimStart(); headers[sp[0]] = sp[1].TrimStart();

1
src/Avalonia.MicroCom/Avalonia.MicroCom.csproj

@ -4,6 +4,7 @@
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="MicroCom.Runtime" Version="0.10.5" />
<ProjectReference Include="..\Avalonia.Build.Tasks\Avalonia.Build.Tasks.csproj"> <ProjectReference Include="..\Avalonia.Build.Tasks\Avalonia.Build.Tasks.csproj">
<ReferenceOutputAssembly>false</ReferenceOutputAssembly> <ReferenceOutputAssembly>false</ReferenceOutputAssembly>
<ExcludeAssets>all</ExcludeAssets> <ExcludeAssets>all</ExcludeAssets>

4
src/Avalonia.MicroCom/CallbackBase.cs

@ -1,4 +1,6 @@
namespace Avalonia.MicroCom using MicroCom.Runtime;
namespace Avalonia.MicroCom
{ {
public abstract class CallbackBase : IUnknown, IMicroComShadowContainer public abstract class CallbackBase : IUnknown, IMicroComShadowContainer
{ {

9
src/Avalonia.MicroCom/IMicroComExceptionCallback.cs

@ -1,9 +0,0 @@
using System;
namespace Avalonia.MicroCom
{
public interface IMicroComExceptionCallback
{
void RaiseException(Exception e);
}
}

9
src/Avalonia.MicroCom/IMicroComShadowContainer.cs

@ -1,9 +0,0 @@
namespace Avalonia.MicroCom
{
public interface IMicroComShadowContainer
{
MicroComShadow Shadow { get; set; }
void OnReferencedFromNative();
void OnUnreferencedFromNative();
}
}

8
src/Avalonia.MicroCom/IUnknown.cs

@ -1,8 +0,0 @@
using System;
namespace Avalonia.MicroCom
{
public interface IUnknown : IDisposable
{
}
}

17
src/Avalonia.MicroCom/LocalInterop.cs

@ -1,17 +0,0 @@
using System;
namespace Avalonia.MicroCom
{
unsafe class LocalInterop
{
public static unsafe void CalliStdCallvoid(void* thisObject, void* methodPtr)
{
throw null;
}
public static unsafe int CalliStdCallint(void* thisObject, Guid* guid, IntPtr* ppv, void* methodPtr)
{
throw null;
}
}
}

110
src/Avalonia.MicroCom/MicroComProxyBase.cs

@ -1,110 +0,0 @@
using System;
using System.Runtime.ConstrainedExecution;
using System.Runtime.InteropServices;
using System.Threading;
namespace Avalonia.MicroCom
{
public unsafe class MicroComProxyBase : CriticalFinalizerObject, IUnknown
{
private IntPtr _nativePointer;
private bool _ownsHandle;
private SynchronizationContext _synchronizationContext;
public IntPtr NativePointer
{
get
{
if (_nativePointer == IntPtr.Zero)
throw new ObjectDisposedException(this.GetType().FullName);
return _nativePointer;
}
}
public void*** PPV => (void***)NativePointer;
public MicroComProxyBase(IntPtr nativePointer, bool ownsHandle)
{
_nativePointer = nativePointer;
_ownsHandle = ownsHandle;
_synchronizationContext = SynchronizationContext.Current;
if(!_ownsHandle)
GC.SuppressFinalize(this);
}
protected virtual int VTableSize => 3;
public void AddRef()
{
LocalInterop.CalliStdCallvoid(PPV, (*PPV)[1]);
}
public void Release()
{
LocalInterop.CalliStdCallvoid(PPV, (*PPV)[2]);
}
public int QueryInterface(Guid guid, out IntPtr ppv)
{
IntPtr r = default;
var rv = LocalInterop.CalliStdCallint(PPV, &guid, &r, (*PPV)[0]);
ppv = r;
return rv;
}
public T QueryInterface<T>() where T : IUnknown
{
var guid = MicroComRuntime.GetGuidFor(typeof(T));
var rv = QueryInterface(guid, out var ppv);
if (rv == 0)
return (T)MicroComRuntime.CreateProxyFor(typeof(T), ppv, true);
throw new COMException("QueryInterface failed", rv);
}
public bool IsDisposed => _nativePointer == IntPtr.Zero;
protected virtual void Dispose(bool disposing)
{
if(_nativePointer == IntPtr.Zero)
return;
if (_ownsHandle)
{
Release();
_ownsHandle = false;
}
_nativePointer = IntPtr.Zero;
GC.SuppressFinalize(this);
}
public void Dispose() => Dispose(true);
public bool OwnsHandle => _ownsHandle;
public void EnsureOwned()
{
if (!_ownsHandle)
{
GC.ReRegisterForFinalize(true);
AddRef();
_ownsHandle = true;
}
}
private static readonly SendOrPostCallback _disposeDelegate = DisposeOnContext;
private static void DisposeOnContext(object state)
{
(state as MicroComProxyBase)?.Dispose(false);
}
~MicroComProxyBase()
{
if(!_ownsHandle)
return;
if (_synchronizationContext == null)
Dispose();
else
_synchronizationContext.Post(_disposeDelegate, this);
}
}
}

143
src/Avalonia.MicroCom/MicroComRuntime.cs

@ -1,143 +0,0 @@
using System;
using System.Collections.Concurrent;
using System.Runtime.InteropServices;
namespace Avalonia.MicroCom
{
public static unsafe class MicroComRuntime
{
private static ConcurrentDictionary<Type, IntPtr> _vtables = new ConcurrentDictionary<Type, IntPtr>();
private static ConcurrentDictionary<Type, Func<IntPtr, bool, object>> _factories =
new ConcurrentDictionary<Type, Func<IntPtr, bool, object>>();
private static ConcurrentDictionary<Type, Guid> _guids = new ConcurrentDictionary<Type, Guid>();
private static ConcurrentDictionary<Guid, Type> _guidsToTypes = new ConcurrentDictionary<Guid, Type>();
internal static readonly Guid ManagedObjectInterfaceGuid = Guid.Parse("cd7687c0-a9c2-4563-b08e-a399df50c633");
static MicroComRuntime()
{
Register(typeof(IUnknown), new Guid("00000000-0000-0000-C000-000000000046"),
(ppv, owns) => new MicroComProxyBase(ppv, owns));
RegisterVTable(typeof(IUnknown), MicroComVtblBase.Vtable);
}
public static void RegisterVTable(Type t, IntPtr vtable)
{
_vtables[t] = vtable;
}
public static void Register(Type t, Guid guid, Func<IntPtr, bool, object> proxyFactory)
{
_factories[t] = proxyFactory;
_guids[t] = guid;
_guidsToTypes[guid] = t;
}
public static Guid GetGuidFor(Type type) => _guids[type];
public static T CreateProxyFor<T>(void* pObject, bool ownsHandle) => (T)CreateProxyFor(typeof(T), new IntPtr(pObject), ownsHandle);
public static T CreateProxyFor<T>(IntPtr pObject, bool ownsHandle) => (T)CreateProxyFor(typeof(T), pObject, ownsHandle);
public static T CreateProxyOrNullFor<T>(void* pObject, bool ownsHandle) where T : class =>
pObject == null ? null : (T)CreateProxyFor(typeof(T), new IntPtr(pObject), ownsHandle);
public static T CreateProxyOrNullFor<T>(IntPtr pObject, bool ownsHandle) where T : class =>
pObject == IntPtr.Zero ? null : (T)CreateProxyFor(typeof(T), pObject, ownsHandle);
public static object CreateProxyFor(Type type, IntPtr pObject, bool ownsHandle) => _factories[type](pObject, ownsHandle);
public static IntPtr GetNativeIntPtr<T>(this T obj, bool owned = false) where T : IUnknown
=> new IntPtr(GetNativePointer(obj, owned));
public static void* GetNativePointer<T>(T obj, bool owned = false) where T : IUnknown
{
if (obj == null)
return null;
if (obj is MicroComProxyBase proxy)
{
if(owned)
proxy.AddRef();
return (void*)proxy.NativePointer;
}
if (obj is IMicroComShadowContainer container)
{
container.Shadow ??= new MicroComShadow(container);
void* ptr = null;
var res = container.Shadow.GetOrCreateNativePointer(typeof(T), &ptr);
if (res != 0)
throw new COMException(
"Unable to create native callable wrapper for type " + typeof(T) + " for instance of type " +
obj.GetType(),
res);
if (owned)
container.Shadow.AddRef((Ccw*)ptr);
return ptr;
}
throw new ArgumentException("Unable to get a native pointer for " + obj);
}
public static object GetObjectFromCcw(IntPtr ccw)
{
var ptr = (Ccw*)ccw;
var shadow = (MicroComShadow)GCHandle.FromIntPtr(ptr->GcShadowHandle).Target;
return shadow.Target;
}
public static bool IsComWrapper(IUnknown obj) => obj is MicroComProxyBase;
public static object TryUnwrapManagedObject(IUnknown obj)
{
if (obj is not MicroComProxyBase proxy)
return null;
if (proxy.QueryInterface(ManagedObjectInterfaceGuid, out _) != 0)
return null;
// Successful QueryInterface always increments ref counter
proxy.Release();
return GetObjectFromCcw(proxy.NativePointer);
}
public static bool TryGetTypeForGuid(Guid guid, out Type t) => _guidsToTypes.TryGetValue(guid, out t);
public static bool GetVtableFor(Type type, out IntPtr ptr) => _vtables.TryGetValue(type, out ptr);
public static void UnhandledException(object target, Exception e)
{
if (target is IMicroComExceptionCallback cb)
{
try
{
cb.RaiseException(e);
}
catch
{
// We've tried
}
}
}
public static T CloneReference<T>(this T iface) where T : IUnknown
{
var proxy = (MicroComProxyBase)(object)iface;
var ownedPointer = GetNativePointer(iface, true);
return CreateProxyFor<T>(ownedPointer, true);
}
public static T QueryInterface<T>(this IUnknown unknown) where T : IUnknown
{
var proxy = (MicroComProxyBase)unknown;
return proxy.QueryInterface<T>();
}
public static void UnsafeAddRef(this IUnknown unknown)
{
((MicroComProxyBase)unknown).AddRef();
}
public static void UnsafeRelease(this IUnknown unknown)
{
((MicroComProxyBase)unknown).Release();
}
}
}

177
src/Avalonia.MicroCom/MicroComShadow.cs

@ -1,177 +0,0 @@
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Threading;
namespace Avalonia.MicroCom
{
public unsafe class MicroComShadow : IDisposable
{
private readonly object _lock = new object();
private readonly Dictionary<Type, IntPtr> _shadows = new Dictionary<Type, IntPtr>();
private readonly Dictionary<IntPtr, Type> _backShadows = new Dictionary<IntPtr, Type>();
private GCHandle? _handle;
private volatile int _refCount;
internal IMicroComShadowContainer Target { get; }
internal MicroComShadow(IMicroComShadowContainer target)
{
Target = target;
Target.Shadow = this;
}
internal int QueryInterface(Ccw* ccw, Guid* guid, void** ppv)
{
if (MicroComRuntime.TryGetTypeForGuid(*guid, out var type))
return QueryInterface(type, ppv);
else if (*guid == MicroComRuntime.ManagedObjectInterfaceGuid)
{
ccw->RefCount++;
*ppv = ccw;
return 0;
}
else
return unchecked((int)0x80004002u);
}
internal int QueryInterface(Type type, void** ppv)
{
if (!type.IsInstanceOfType(Target))
return unchecked((int)0x80004002u);
var rv = GetOrCreateNativePointer(type, ppv);
if (rv == 0)
AddRef((Ccw*)*ppv);
return rv;
}
internal int GetOrCreateNativePointer(Type type, void** ppv)
{
if (!MicroComRuntime.GetVtableFor(type, out var vtable))
return unchecked((int)0x80004002u);
lock (_lock)
{
if (_shadows.TryGetValue(type, out var shadow))
{
var targetCcw = (Ccw*)shadow;
AddRef(targetCcw);
*ppv = targetCcw;
return 0;
}
else
{
var intPtr = Marshal.AllocHGlobal(Marshal.SizeOf<Ccw>());
var targetCcw = (Ccw*)intPtr;
*targetCcw = default;
targetCcw->RefCount = 0;
targetCcw->VTable = vtable;
if (_handle == null)
_handle = GCHandle.Alloc(this);
targetCcw->GcShadowHandle = GCHandle.ToIntPtr(_handle.Value);
_shadows[type] = intPtr;
_backShadows[intPtr] = type;
*ppv = targetCcw;
return 0;
}
}
}
internal int AddRef(Ccw* ccw)
{
if (Interlocked.Increment(ref _refCount) == 1)
{
try
{
Target.OnReferencedFromNative();
}
catch (Exception e)
{
MicroComRuntime.UnhandledException(Target, e);
}
}
return Interlocked.Increment(ref ccw->RefCount);
}
internal int Release(Ccw* ccw)
{
Interlocked.Decrement(ref _refCount);
var cnt = Interlocked.Decrement(ref ccw->RefCount);
if (cnt == 0)
return FreeCcw(ccw);
return cnt;
}
int FreeCcw(Ccw* ccw)
{
lock (_lock)
{
// Shadow got resurrected by a call to QueryInterface from another thread
if (ccw->RefCount != 0)
return ccw->RefCount;
var intPtr = new IntPtr(ccw);
var type = _backShadows[intPtr];
_backShadows.Remove(intPtr);
_shadows.Remove(type);
Marshal.FreeHGlobal(intPtr);
if (_shadows.Count == 0)
{
_handle?.Free();
_handle = null;
try
{
Target.OnUnreferencedFromNative();
}
catch(Exception e)
{
MicroComRuntime.UnhandledException(Target, e);
}
}
}
return 0;
}
/*
Needs to be called to support the following scenario:
1) Object created
2) Object passed to native code, shadow is created, CCW is created
3) Native side has never called AddRef
In that case the GC handle to the shadow object is still alive
*/
public void Dispose()
{
lock (_lock)
{
List<IntPtr> toRemove = null;
foreach (var kv in _backShadows)
{
var ccw = (Ccw*)kv.Key;
if (ccw->RefCount == 0)
{
toRemove ??= new List<IntPtr>();
toRemove.Add(kv.Key);
}
}
if(toRemove != null)
foreach (var intPtr in toRemove)
FreeCcw((Ccw*)intPtr);
}
}
}
[StructLayout(LayoutKind.Sequential)]
struct Ccw
{
public IntPtr VTable;
public IntPtr GcShadowHandle;
public volatile int RefCount;
public MicroComShadow GetShadow() => (MicroComShadow)GCHandle.FromIntPtr(GcShadowHandle).Target;
}
}

47
src/Avalonia.MicroCom/MicroComVtblBase.cs

@ -1,47 +0,0 @@
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
namespace Avalonia.MicroCom
{
public unsafe class MicroComVtblBase
{
private List<IntPtr> _methods = new List<IntPtr>();
[UnmanagedFunctionPointerAttribute(CallingConvention.StdCall)]
private delegate int AddRefDelegate(Ccw* ccw);
[UnmanagedFunctionPointerAttribute(CallingConvention.StdCall)]
private delegate int QueryInterfaceDelegate(Ccw* ccw, Guid* guid, void** ppv);
public static IntPtr Vtable { get; } = new MicroComVtblBase().CreateVTable();
public MicroComVtblBase()
{
AddMethod((QueryInterfaceDelegate)QueryInterface);
AddMethod((AddRefDelegate)AddRef);
AddMethod((AddRefDelegate)Release);
}
protected void AddMethod(void* f)
{
_methods.Add(new IntPtr(f));
}
protected void AddMethod(Delegate d)
{
GCHandle.Alloc(d);
_methods.Add(Marshal.GetFunctionPointerForDelegate(d));
}
protected unsafe IntPtr CreateVTable()
{
var ptr = (IntPtr*)Marshal.AllocHGlobal((IntPtr.Size + 1) * _methods.Count);
for (var c = 0; c < _methods.Count; c++)
ptr[c] = _methods[c];
return new IntPtr(ptr);
}
static int QueryInterface(Ccw* ccw, Guid* guid, void** ppv) => ccw->GetShadow().QueryInterface(ccw, guid, ppv);
static int AddRef(Ccw* ccw) => ccw->GetShadow().AddRef(ccw);
static int Release(Ccw* ccw) => ccw->GetShadow().Release(ccw);
}
}

1
src/Avalonia.Native/Avalonia.Native.csproj

@ -6,7 +6,6 @@
<IsPackable Condition="'$([MSBuild]::IsOSPlatform(OSX))' == 'True'">true</IsPackable> <IsPackable Condition="'$([MSBuild]::IsOSPlatform(OSX))' == 'True'">true</IsPackable>
<TargetFrameworks>net6.0;netstandard2.0</TargetFrameworks> <TargetFrameworks>net6.0;netstandard2.0</TargetFrameworks>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<MicroComGeneratorRuntimeNamespace>Avalonia.MicroCom</MicroComGeneratorRuntimeNamespace>
</PropertyGroup> </PropertyGroup>
<ItemGroup Condition="'$(PackAvaloniaNative)' == 'true'"> <ItemGroup Condition="'$(PackAvaloniaNative)' == 'true'">

1
src/Avalonia.Native/AvaloniaNativePlatform.cs

@ -10,6 +10,7 @@ using Avalonia.Platform;
using Avalonia.Rendering; using Avalonia.Rendering;
using Avalonia.Rendering.Composition; using Avalonia.Rendering.Composition;
using JetBrains.Annotations; using JetBrains.Annotations;
using MicroCom.Runtime;
namespace Avalonia.Native namespace Avalonia.Native
{ {

1
src/Avalonia.Native/CallbackBase.cs

@ -2,6 +2,7 @@
using System.Runtime.ExceptionServices; using System.Runtime.ExceptionServices;
using Avalonia.MicroCom; using Avalonia.MicroCom;
using Avalonia.Platform; using Avalonia.Platform;
using MicroCom.Runtime;
namespace Avalonia.Native namespace Avalonia.Native
{ {

1
src/Avalonia.Native/NativeControlHostImpl.cs

@ -4,6 +4,7 @@ using Avalonia.MicroCom;
using Avalonia.Native.Interop; using Avalonia.Native.Interop;
using Avalonia.Platform; using Avalonia.Platform;
using Avalonia.VisualTree; using Avalonia.VisualTree;
using MicroCom.Runtime;
namespace Avalonia.Native namespace Avalonia.Native
{ {

2
src/Avalonia.X11/X11Structs.cs

@ -661,7 +661,7 @@ namespace Avalonia.X11 {
Type type = ev.GetType (); Type type = ev.GetType ();
FieldInfo [] fields = type.GetFields (System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Instance); FieldInfo [] fields = type.GetFields (System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Instance);
for (int i = 0; i < fields.Length; i++) { for (int i = 0; i < fields.Length; i++) {
if (result != string.Empty) { if (!string.IsNullOrEmpty(result)) {
result += ", "; result += ", ";
} }
object value = fields [i].GetValue (ev); object value = fields [i].GetValue (ev);

18
src/Markup/Avalonia.Markup/Markup/Parsers/SelectorGrammar.cs

@ -376,28 +376,28 @@ namespace Avalonia.Markup.Parsers
if (r.Peek == 'o') if (r.Peek == 'o')
{ {
var constArg = r.TakeUntil(')').ToString().Trim(); var constArg = r.TakeUntil(')').Trim();
if (constArg.Equals("odd", StringComparison.Ordinal)) if (constArg.SequenceEqual("odd".AsSpan()))
{ {
step = 2; step = 2;
offset = 1; offset = 1;
} }
else else
{ {
throw new ExpressionParseException(r.Position, $"Expected nth-child(odd). Actual '{constArg}'."); throw new ExpressionParseException(r.Position, $"Expected nth-child(odd). Actual '{constArg.ToString()}'.");
} }
} }
else if (r.Peek == 'e') else if (r.Peek == 'e')
{ {
var constArg = r.TakeUntil(')').ToString().Trim(); var constArg = r.TakeUntil(')').Trim();
if (constArg.Equals("even", StringComparison.Ordinal)) if (constArg.SequenceEqual("even".AsSpan()))
{ {
step = 2; step = 2;
offset = 0; offset = 0;
} }
else else
{ {
throw new ExpressionParseException(r.Position, $"Expected nth-child(even). Actual '{constArg}'."); throw new ExpressionParseException(r.Position, $"Expected nth-child(even). Actual '{constArg.ToString()}'.");
} }
} }
else else
@ -405,7 +405,7 @@ namespace Avalonia.Markup.Parsers
r.SkipWhitespace(); r.SkipWhitespace();
var stepOrOffset = 0; var stepOrOffset = 0;
var stepOrOffsetStr = r.TakeWhile(c => char.IsDigit(c) || c == '-' || c == '+').ToString(); var stepOrOffsetStr = r.TakeWhile(c => char.IsDigit(c) || c == '-' || c == '+');
if (stepOrOffsetStr.Length == 0 if (stepOrOffsetStr.Length == 0
|| (stepOrOffsetStr.Length == 1 || (stepOrOffsetStr.Length == 1
&& stepOrOffsetStr[0] == '+')) && stepOrOffsetStr[0] == '+'))
@ -417,7 +417,7 @@ namespace Avalonia.Markup.Parsers
{ {
stepOrOffset = -1; stepOrOffset = -1;
} }
else if (!int.TryParse(stepOrOffsetStr.ToString(), out stepOrOffset)) else if (!stepOrOffsetStr.TryParseInt(out stepOrOffset))
{ {
throw new ExpressionParseException(r.Position, "Couldn't parse nth-child step or offset value. Integer was expected."); throw new ExpressionParseException(r.Position, "Couldn't parse nth-child step or offset value. Integer was expected.");
} }
@ -462,7 +462,7 @@ namespace Avalonia.Markup.Parsers
r.SkipWhitespace(); r.SkipWhitespace();
if (sign != 0 if (sign != 0
&& !int.TryParse(r.TakeUntil(')').ToString(), out offset)) && !r.TakeUntil(')').TryParseInt(out offset))
{ {
throw new ExpressionParseException(r.Position, "Couldn't parse nth-child offset value. Integer was expected."); throw new ExpressionParseException(r.Position, "Couldn't parse nth-child offset value. Integer was expected.");
} }

1
src/Windows/Avalonia.Win32/Avalonia.Win32.csproj

@ -3,7 +3,6 @@
<TargetFrameworks>net6.0;netstandard2.0</TargetFrameworks> <TargetFrameworks>net6.0;netstandard2.0</TargetFrameworks>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<PackageId>Avalonia.Win32</PackageId> <PackageId>Avalonia.Win32</PackageId>
<MicroComGeneratorRuntimeNamespace>Avalonia.MicroCom</MicroComGeneratorRuntimeNamespace>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="System.Numerics.Vectors" Version="4.5.0" /> <PackageReference Include="System.Numerics.Vectors" Version="4.5.0" />

7
src/Windows/Avalonia.Win32/ClipboardImpl.cs

@ -7,6 +7,7 @@ using Avalonia.Input;
using Avalonia.Input.Platform; using Avalonia.Input.Platform;
using Avalonia.Threading; using Avalonia.Threading;
using Avalonia.Win32.Interop; using Avalonia.Win32.Interop;
using MicroCom.Runtime;
namespace Avalonia.Win32 namespace Avalonia.Win32
{ {
@ -83,7 +84,7 @@ namespace Avalonia.Win32
while (true) while (true)
{ {
var ptr = MicroCom.MicroComRuntime.GetNativeIntPtr<Win32Com.IDataObject>(wrapper); var ptr = wrapper.GetNativeIntPtr<Win32Com.IDataObject>();
var hr = UnmanagedMethods.OleSetClipboard(ptr); var hr = UnmanagedMethods.OleSetClipboard(ptr);
if (hr == 0) if (hr == 0)
@ -107,7 +108,7 @@ namespace Avalonia.Win32
if (hr == 0) if (hr == 0)
{ {
using var proxy = MicroCom.MicroComRuntime.CreateProxyFor<Win32Com.IDataObject>(dataObject, true); using var proxy = MicroComRuntime.CreateProxyFor<Win32Com.IDataObject>(dataObject, true);
using var wrapper = new OleDataObject(proxy); using var wrapper = new OleDataObject(proxy);
var formats = wrapper.GetDataFormats().ToArray(); var formats = wrapper.GetDataFormats().ToArray();
return formats; return formats;
@ -131,7 +132,7 @@ namespace Avalonia.Win32
if (hr == 0) if (hr == 0)
{ {
using var proxy = MicroCom.MicroComRuntime.CreateProxyFor<Win32Com.IDataObject>(dataObject, true); using var proxy = MicroComRuntime.CreateProxyFor<Win32Com.IDataObject>(dataObject, true);
using var wrapper = new OleDataObject(proxy); using var wrapper = new OleDataObject(proxy);
var rv = wrapper.Get(format); var rv = wrapper.Get(format);
return rv; return rv;

5
src/Windows/Avalonia.Win32/DragSource.cs

@ -3,6 +3,7 @@ using Avalonia.Input;
using Avalonia.Input.Platform; using Avalonia.Input.Platform;
using Avalonia.Threading; using Avalonia.Threading;
using Avalonia.Win32.Interop; using Avalonia.Win32.Interop;
using MicroCom.Runtime;
namespace Avalonia.Win32 namespace Avalonia.Win32
{ {
@ -19,8 +20,8 @@ namespace Avalonia.Win32
using var src = new OleDragSource(); using var src = new OleDragSource();
var allowed = OleDropTarget.ConvertDropEffect(allowedEffects); var allowed = OleDropTarget.ConvertDropEffect(allowedEffects);
var objPtr = MicroCom.MicroComRuntime.GetNativeIntPtr<Win32Com.IDataObject>(dataObject); var objPtr = MicroComRuntime.GetNativeIntPtr<Win32Com.IDataObject>(dataObject);
var srcPtr = MicroCom.MicroComRuntime.GetNativeIntPtr<Win32Com.IDropSource>(src); var srcPtr = MicroComRuntime.GetNativeIntPtr<Win32Com.IDropSource>(src);
UnmanagedMethods.DoDragDrop(objPtr, srcPtr, (int)allowed, out var finalEffect); UnmanagedMethods.DoDragDrop(objPtr, srcPtr, (int)allowed, out var finalEffect);

1
src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs

@ -7,6 +7,7 @@ using System.Runtime.InteropServices.ComTypes;
using System.Text; using System.Text;
using Avalonia.MicroCom; using Avalonia.MicroCom;
using MicroCom.Runtime;
using Avalonia.Win32.Win32Com; using Avalonia.Win32.Win32Com;
// ReSharper disable InconsistentNaming // ReSharper disable InconsistentNaming

3
src/Windows/Avalonia.Win32/OleContext.cs

@ -5,6 +5,7 @@ using Avalonia.Platform;
using Avalonia.Threading; using Avalonia.Threading;
using Avalonia.Win32.Interop; using Avalonia.Win32.Interop;
using Avalonia.Win32.Win32Com; using Avalonia.Win32.Win32Com;
using MicroCom.Runtime;
namespace Avalonia.Win32 namespace Avalonia.Win32
{ {
@ -47,7 +48,7 @@ namespace Avalonia.Win32
return false; return false;
} }
var trgPtr = MicroCom.MicroComRuntime.GetNativeIntPtr(target); var trgPtr = target.GetNativeIntPtr();
return UnmanagedMethods.RegisterDragDrop(hwnd.Handle, trgPtr) == UnmanagedMethods.HRESULT.S_OK; return UnmanagedMethods.RegisterDragDrop(hwnd.Handle, trgPtr) == UnmanagedMethods.HRESULT.S_OK;
} }

2
src/Windows/Avalonia.Win32/OleDataObject.cs

@ -10,7 +10,7 @@ using Avalonia.Input;
using Avalonia.MicroCom; using Avalonia.MicroCom;
using Avalonia.Utilities; using Avalonia.Utilities;
using Avalonia.Win32.Interop; using Avalonia.Win32.Interop;
using MicroCom.Runtime;
using IDataObject = Avalonia.Input.IDataObject; using IDataObject = Avalonia.Input.IDataObject;
namespace Avalonia.Win32 namespace Avalonia.Win32

1
src/Windows/Avalonia.Win32/OleDropTarget.cs

@ -5,6 +5,7 @@ using Avalonia.Input.Raw;
using Avalonia.MicroCom; using Avalonia.MicroCom;
using Avalonia.Platform; using Avalonia.Platform;
using Avalonia.Win32.Interop; using Avalonia.Win32.Interop;
using MicroCom.Runtime;
using DropEffect = Avalonia.Win32.Win32Com.DropEffect; using DropEffect = Avalonia.Win32.Win32Com.DropEffect;
namespace Avalonia.Win32 namespace Avalonia.Win32

1
src/Windows/Avalonia.Win32/Win32StorageProvider.cs

@ -12,6 +12,7 @@ using Avalonia.Platform.Storage;
using Avalonia.Platform.Storage.FileIO; using Avalonia.Platform.Storage.FileIO;
using Avalonia.Win32.Interop; using Avalonia.Win32.Interop;
using Avalonia.Win32.Win32Com; using Avalonia.Win32.Win32Com;
using MicroCom.Runtime;
namespace Avalonia.Win32 namespace Avalonia.Win32
{ {

1
src/Windows/Avalonia.Win32/WinRT/Composition/WinUICompositedWindow.cs

@ -6,6 +6,7 @@ using Avalonia.MicroCom;
using Avalonia.OpenGL; using Avalonia.OpenGL;
using Avalonia.OpenGL.Egl; using Avalonia.OpenGL.Egl;
using Avalonia.Win32.Interop; using Avalonia.Win32.Interop;
using MicroCom.Runtime;
namespace Avalonia.Win32.WinRT.Composition namespace Avalonia.Win32.WinRT.Composition
{ {

1
src/Windows/Avalonia.Win32/WinRT/Composition/WinUICompositorConnection.cs

@ -12,6 +12,7 @@ using Avalonia.OpenGL.Angle;
using Avalonia.OpenGL.Egl; using Avalonia.OpenGL.Egl;
using Avalonia.Rendering; using Avalonia.Rendering;
using Avalonia.Win32.Interop; using Avalonia.Win32.Interop;
using MicroCom.Runtime;
namespace Avalonia.Win32.WinRT.Composition namespace Avalonia.Win32.WinRT.Composition
{ {

1
src/Windows/Avalonia.Win32/WinRT/Composition/WinUIEffectBase.cs

@ -2,6 +2,7 @@
using System.Linq; using System.Linq;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using Avalonia.MicroCom; using Avalonia.MicroCom;
using MicroCom.Runtime;
namespace Avalonia.Win32.WinRT.Composition namespace Avalonia.Win32.WinRT.Composition
{ {

1
src/Windows/Avalonia.Win32/WinRT/Composition/WinUiCompositedWindowSurface.cs

@ -6,6 +6,7 @@ using Avalonia.OpenGL.Egl;
using Avalonia.OpenGL.Surfaces; using Avalonia.OpenGL.Surfaces;
using Avalonia.Utilities; using Avalonia.Utilities;
using Avalonia.Win32.Interop; using Avalonia.Win32.Interop;
using MicroCom.Runtime;
namespace Avalonia.Win32.WinRT.Composition namespace Avalonia.Win32.WinRT.Composition
{ {

1
src/Windows/Avalonia.Win32/WinRT/NativeWinRTMethods.cs

@ -7,6 +7,7 @@ using System.Runtime.InteropServices;
using System.Threading; using System.Threading;
using Avalonia.MicroCom; using Avalonia.MicroCom;
using Avalonia.Win32.Interop; using Avalonia.Win32.Interop;
using MicroCom.Runtime;
namespace Avalonia.Win32.WinRT namespace Avalonia.Win32.WinRT
{ {

1
src/Windows/Avalonia.Win32/WinRT/WinRTInspectable.cs

@ -3,6 +3,7 @@ using System.Linq;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using Avalonia.MicroCom; using Avalonia.MicroCom;
using MicroCom.Runtime;
namespace Avalonia.Win32.WinRT namespace Avalonia.Win32.WinRT
{ {

2
tests/Avalonia.Base.UnitTests/Media/TextFormatting/GraphemeBreakTestDataGenerator.cs

@ -80,7 +80,7 @@ namespace Avalonia.Visuals.UnitTests.Media.TextFormatting
var remaining = remainingChars.Where(x => x != "" && x != "×").Select(x => Convert.ToInt32(x, 16)).ToArray(); var remaining = remainingChars.Where(x => x != "" && x != "×").Select(x => Convert.ToInt32(x, 16)).ToArray();
codepoints.AddRange(remaining); codepoints.AddRange(remaining);
} }
var data = new GraphemeBreakData var data = new GraphemeBreakData
{ {

1
tests/Avalonia.Benchmarks/Avalonia.Benchmarks.csproj

@ -1,6 +1,5 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net6.0</TargetFramework>
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>
<IsPackable>false</IsPackable> <IsPackable>false</IsPackable>

Loading…
Cancel
Save