diff --git a/src/Windows/Avalonia.Win32.Automation/Avalonia.Win32.Automation.csproj b/src/Windows/Avalonia.Win32.Automation/Avalonia.Win32.Automation.csproj
index c56131c495..0d30f8e74b 100644
--- a/src/Windows/Avalonia.Win32.Automation/Avalonia.Win32.Automation.csproj
+++ b/src/Windows/Avalonia.Win32.Automation/Avalonia.Win32.Automation.csproj
@@ -15,5 +15,6 @@
+
diff --git a/src/Windows/Avalonia.Win32.Automation/Marshalling/SafeArrayMarshaller.cs b/src/Windows/Avalonia.Win32.Automation/Marshalling/SafeArrayMarshaller.cs
index ef3af4a3b2..a82ad213c4 100644
--- a/src/Windows/Avalonia.Win32.Automation/Marshalling/SafeArrayMarshaller.cs
+++ b/src/Windows/Avalonia.Win32.Automation/Marshalling/SafeArrayMarshaller.cs
@@ -10,7 +10,7 @@ internal static class SafeArrayMarshaller where T : notnull
{
public static SafeArrayRef ConvertToUnmanaged(T[]? managed) =>
managed is null ? new SafeArrayRef()
- : SafeArrayRef.TryCreate(managed, out var result, out _) ? result.Value
+ : SafeArrayRef.TryCreate(managed, out var result, out _) ? result.Value
: throw new NotImplementedException($"SafeArray marshalling for '{managed?.GetType().Name}' is not implemented.");
public static T[]? ConvertToManaged(SafeArrayRef unmanaged) => SafeArrayRef.ToArray(unmanaged);
diff --git a/src/Windows/Avalonia.Win32.Automation/Marshalling/SafeArrayRef.cs b/src/Windows/Avalonia.Win32.Automation/Marshalling/SafeArrayRef.cs
index f27c67e36e..b4c2e53710 100644
--- a/src/Windows/Avalonia.Win32.Automation/Marshalling/SafeArrayRef.cs
+++ b/src/Windows/Avalonia.Win32.Automation/Marshalling/SafeArrayRef.cs
@@ -8,6 +8,7 @@ using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
+using System.Runtime.InteropServices.Marshalling;
// ReSharper disable InconsistentNaming
namespace Avalonia.Win32.Automation.Marshalling;
@@ -160,6 +161,25 @@ internal unsafe partial struct SafeArrayRef
});
}
+ ///
+ /// Creates a SAFEARRAY from a typed array.
+ ///
+ ///
+ /// COM interfaces have to come through here rather than through the non-generic overload: the
+ /// element type is what tells us to wrap each item, and it isn't recoverable from the values.
+ ///
+ public static bool TryCreate(T[]? managed, [NotNullWhen(true)] out SafeArrayRef? safearray, out VarEnum varEnum)
+ {
+ if (managed is not null && typeof(T).IsInterface)
+ {
+ safearray = CreateFromComObjects(managed);
+ varEnum = VarEnum.VT_UNKNOWN;
+ return true;
+ }
+
+ return TryCreate((IEnumerable?)managed, out safearray, out varEnum);
+ }
+
public static bool TryCreate(IEnumerable? managed, [NotNullWhen(true)] out SafeArrayRef? safearray, out VarEnum varEnum)
{
safearray = default;
@@ -181,38 +201,6 @@ internal unsafe partial struct SafeArrayRef
return CreateFromSpan(collectionSpan, varEnum);
}
- static SafeArrayRef CreateFromSpan(ReadOnlySpan span, VarEnum varEnum)
- {
- var bound = new SAFEARRAYBOUND { cElements = (uint)span.Length, lLbound = 0 };
- var safearray = SafeArrayCreate(varEnum, 1, bound);
- if (span.Length == 0)
- {
- return new SafeArrayRef
- {
- _ptr = safearray
- };
- }
-
- var lockResult = SafeArrayLock(safearray);
- if (lockResult != 0) throw new Win32Exception(lockResult);
-
- try
- {
- // We assume it has the same length.
- var output = new Span(safearray->pvData, (int)safearray->rgsabound[0].cElements);
- span.CopyTo(output);
- }
- finally
- {
- SafeArrayUnlock(safearray);
- }
-
- return new SafeArrayRef
- {
- _ptr = safearray
- };
- }
-
static SafeArrayRef CreateFromStrings(IReadOnlyList strings, VarEnum varEnum)
{
Debug.Assert(varEnum == VarEnum.VT_BSTR); // other types not supported yet
@@ -251,28 +239,6 @@ internal unsafe partial struct SafeArrayRef
}
}
- static SafeArrayRef CreateFromObjects(IReadOnlyList