Skip to content
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
6 changes: 6 additions & 0 deletions SharpGen.Runtime.Trim.Dummy/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// See https://aka.ms/new-console-template for more information

// I'm a dummy project for testing trimmability, since the analyzer outside of publish time isn't fully perfect yet
// test my trimming with `dotnet publish -r win-x64`

Console.WriteLine("Hello SharpGenTools");
20 changes: 20 additions & 0 deletions SharpGen.Runtime.Trim.Dummy/SharpGen.Runtime.Trim.Dummy.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<PublishTrimmed>true</PublishTrimmed>
<IsPackable>false</IsPackable>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\SharpGen.Runtime\SharpGen.Runtime.csproj" />
</ItemGroup>

<ItemGroup>
<TrimmerRootAssembly Include="SharpGen.Runtime" />
</ItemGroup>

</Project>
37 changes: 31 additions & 6 deletions SharpGen.Runtime/COM/ComObject.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#nullable enable

using System;
using System.Diagnostics.CodeAnalysis;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
Expand Down Expand Up @@ -110,7 +111,11 @@ public virtual IntPtr QueryInterfaceOrNull(Guid guid)
/// <msdn-id>ms682521</msdn-id>
/// <unmanaged>IUnknown::QueryInterface</unmanaged>
/// <unmanaged-short>IUnknown::QueryInterface</unmanaged-short>
public virtual T QueryInterface<T>() where T : ComObject
public virtual T QueryInterface<
#if NET5_0_OR_GREATER
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)]
#endif
T>() where T : ComObject
{
QueryInterface(typeof(T).GetTypeInfo().GUID, out var parentPtr).CheckError();
return MarshallingHelpers.FromPointer<T>(parentPtr)!;
Expand All @@ -128,7 +133,11 @@ public virtual T QueryInterface<T>() where T : ComObject
#if NET5_0_OR_GREATER
[SupportedOSPlatform("windows")]
#endif
public static T As<T>(object comObject) where T : ComObject => As<T>(Marshal.GetIUnknownForObject(comObject));
public static T As<
#if NET5_0_OR_GREATER
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)]
#endif
T>(object comObject) where T : ComObject => As<T>(Marshal.GetIUnknownForObject(comObject));

/// <summary>
/// Queries a managed object for a particular COM interface support (This method is a shortcut to <see cref="QueryInterface"/>)
Expand All @@ -139,7 +148,11 @@ public virtual T QueryInterface<T>() where T : ComObject
/// <msdn-id>ms682521</msdn-id>
/// <unmanaged>IUnknown::QueryInterface</unmanaged>
/// <unmanaged-short>IUnknown::QueryInterface</unmanaged-short>
public static T As<T>(IntPtr iunknownPtr) where T : ComObject
public static T As<
#if NET5_0_OR_GREATER
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)]
#endif
T>(IntPtr iunknownPtr) where T : ComObject
{
using var tempObject = new ComObject(iunknownPtr);
return tempObject.QueryInterface<T>();
Expand All @@ -157,7 +170,11 @@ public static T As<T>(IntPtr iunknownPtr) where T : ComObject
#if NET5_0_OR_GREATER
[SupportedOSPlatform("windows")]
#endif
public static T QueryInterface<T>(object comObject) where T : ComObject =>
public static T QueryInterface<
#if NET5_0_OR_GREATER
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)]
#endif
T>(object comObject) where T : ComObject =>
As<T>(Marshal.GetIUnknownForObject(comObject));

/// <summary>
Expand All @@ -169,7 +186,11 @@ public static T QueryInterface<T>(object comObject) where T : ComObject =>
/// <msdn-id>ms682521</msdn-id>
/// <unmanaged>IUnknown::QueryInterface</unmanaged>
/// <unmanaged-short>IUnknown::QueryInterface</unmanaged-short>
public static T? QueryInterfaceOrNull<T>(IntPtr comPointer) where T : ComObject
public static T? QueryInterfaceOrNull<
#if NET5_0_OR_GREATER
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)]
#endif
T>(IntPtr comPointer) where T : ComObject
{
using var tempObject = new ComObject(comPointer);
return tempObject.QueryInterfaceOrNull<T>();
Expand All @@ -183,7 +204,11 @@ public static T QueryInterface<T>(object comObject) where T : ComObject =>
/// <msdn-id>ms682521</msdn-id>
/// <unmanaged>IUnknown::QueryInterface</unmanaged>
/// <unmanaged-short>IUnknown::QueryInterface</unmanaged-short>
public virtual T? QueryInterfaceOrNull<T>() where T : ComObject
public virtual T? QueryInterfaceOrNull<
#if NET5_0_OR_GREATER
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)]
#endif
T>() where T : ComObject
{
return MarshallingHelpers.FromPointer<T>(QueryInterfaceOrNull(typeof(T).GetTypeInfo().GUID));
}
Expand Down
38 changes: 34 additions & 4 deletions SharpGen.Runtime/CallbackBase.Reflection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,32 @@

using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Reflection;
using SharpGen.Runtime.TrimmingWrappers;

namespace SharpGen.Runtime;

public abstract partial class CallbackBase
{
private readonly struct ImmediateShadowInterfaceInfo
{
#if NET6_0_OR_GREATER
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.Interfaces)]
#elif NET5_0_OR_GREATER
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)]
#endif
public readonly TypeInfo Type;
public readonly List<TypeInfo> ImplementedInterfaces;

public ImmediateShadowInterfaceInfo(TypeInfo type)
public ImmediateShadowInterfaceInfo(
#if NET6_0_OR_GREATER
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.Interfaces)]
#elif NET5_0_OR_GREATER
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)]
#endif
TypeInfo type)
{
Type = type;
ImplementedInterfaces = new(6);
Expand All @@ -35,16 +48,33 @@ public ImmediateShadowInterfaceInfo(TypeInfo type)
// Cache reflection on interface inheritance
private class CallbackTypeInfo
{
#if NET6_0_OR_GREATER
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.Interfaces)]
#elif NET5_0_OR_GREATER
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)]
#endif
private readonly TypeInfo type;
private ImmediateShadowInterfaceInfo[]? _vtbls;
private TypeInfo[]? _shadows;
private Guid[]? _guids;

public CallbackTypeInfo(Type type) : this(type.GetTypeInfo())
public CallbackTypeInfo(
#if NET6_0_OR_GREATER
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.Interfaces)]
#elif NET5_0_OR_GREATER
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)]
#endif
Type type) : this(type.GetTypeInfo())
{
}

private CallbackTypeInfo(TypeInfo type)
private CallbackTypeInfo(
#if NET6_0_OR_GREATER
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.Interfaces)]
#elif NET5_0_OR_GREATER
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)]
#endif
TypeInfo type)
{
this.type = type ?? throw new ArgumentNullException(nameof(type));
}
Expand Down Expand Up @@ -111,7 +141,7 @@ private ImmediateShadowInterfaceInfo[] BuildVtblList()

foreach (var implementedInterface in type.ImplementedInterfaces)
{
var item = implementedInterface.GetTypeInfo();
var item = implementedInterface.GetTypeInfoWithNestedPreservedInterfaces();

// Only process interfaces that have vtbl
if (!VtblAttribute.Has(item))
Expand Down
3 changes: 2 additions & 1 deletion SharpGen.Runtime/CallbackBase.ReflectionCache.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

using System;
using System.Collections.Generic;
using SharpGen.Runtime.TrimmingWrappers;

namespace SharpGen.Runtime;

Expand All @@ -12,7 +13,7 @@ public abstract partial class CallbackBase
private CallbackTypeInfo GetTypeInfo()
{
CallbackTypeInfo? info;
var type = GetType();
var type = this.GetTypeWithNestedPreservedInterfaces();
var cache = TypeReflectionCache;

lock (cache)
Expand Down
11 changes: 10 additions & 1 deletion SharpGen.Runtime/CallbackBase.ReflectionImpl.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
Expand All @@ -13,7 +14,11 @@ public abstract unsafe partial class CallbackBase
{
protected virtual Guid[] BuildGuidList() => GetTypeInfo().Guids;

private GCHandle CreateShadow(TypeInfo type)
private GCHandle CreateShadow(
#if NET5_0_OR_GREATER
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)]
#endif
TypeInfo type)
{
var shadow = (CppObjectShadow) Activator.CreateInstance(type.AsType())!;

Expand All @@ -23,6 +28,10 @@ private GCHandle CreateShadow(TypeInfo type)
return GCHandle.Alloc(shadow, GCHandleType.Normal);
}

#if NET5_0_OR_GREATER
[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2062", Justification = $"{nameof(ShadowAttribute.Type)} is already marked `DynamicallyAccessedMemberTypes.PublicConstructors` and the existing check via `Debug.Assert(holder.GetTypeInfo().GetConstructor(Type.EmptyTypes)` will ensure correctness.")]
[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2111", Justification = "Same as above.")]
#endif
protected virtual void InitializeCallableWrappers(IDictionary<Guid, IntPtr> ccw)
{
// Associate all shadows with their interfaces.
Expand Down
6 changes: 5 additions & 1 deletion SharpGen.Runtime/InterfaceArray.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,11 @@ namespace SharpGen.Runtime;
[DebuggerTypeProxy(typeof(InterfaceArray<>.InterfaceArrayDebugView))]
[DebuggerDisplay("Count={" + nameof(Length) + "}")]
[SuppressMessage("ReSharper", "ConvertToAutoProperty")]
public unsafe struct InterfaceArray<T> : IReadOnlyList<T>, IEnlightenedDisposable, IDisposable
public unsafe struct InterfaceArray<
#if NET5_0_OR_GREATER
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)]
#endif
T> : IReadOnlyList<T>, IEnlightenedDisposable, IDisposable
where T : CppObject
{
// .NET Native has issues with <...> in property backing fields in structs
Expand Down
13 changes: 11 additions & 2 deletions SharpGen.Runtime/MarshallingHelpers.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#nullable enable

using System;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;

namespace SharpGen.Runtime;
Expand All @@ -13,7 +14,11 @@ public static partial class MarshallingHelpers
/// <typeparam name="T">The CppObject class that will be returned</typeparam>
/// <param name="cppObjectPtr">The native pointer to a C++ object.</param>
/// <returns>An instance of T bound to the native pointer</returns>
public static T? FromPointer<T>(IntPtr cppObjectPtr) where T : CppObject
public static T? FromPointer<
#if NET5_0_OR_GREATER
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)]
#endif
T>(IntPtr cppObjectPtr) where T : CppObject
{
if (cppObjectPtr == IntPtr.Zero)
return default;
Expand All @@ -31,7 +36,11 @@ public static partial class MarshallingHelpers
/// <typeparam name="T">The CppObject class that will be returned</typeparam>
/// <param name="cppObjectPtr">The native pointer to a C++ object.</param>
/// <returns>An instance of T bound to the native pointer</returns>
public static T? FromPointer<T>(UIntPtr cppObjectPtr) where T : CppObject
public static T? FromPointer<
#if NET5_0_OR_GREATER
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)]
#endif
T>(UIntPtr cppObjectPtr) where T : CppObject
{
if (cppObjectPtr == UIntPtr.Zero)
return default;
Expand Down
4 changes: 2 additions & 2 deletions SharpGen.Runtime/NativeLong.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ namespace SharpGen.Runtime;

[StructLayout(LayoutKind.Explicit)]
public readonly struct NativeLong : IEquatable<NativeLong>, IComparable<NativeLong>, IComparable
#if NET5_0
#if NET5_0_OR_GREATER
, IFormattable
#endif
{
Expand Down Expand Up @@ -66,7 +66,7 @@ public override string ToString() =>
public string ToString(string format) =>
UseInt ? _intValue.ToString(format) : _pointerValue.ToString(format);

#if NET5_0
#if NET5_0_OR_GREATER
public string ToString(IFormatProvider formatProvider) =>
UseInt ? _intValue.ToString(formatProvider) : _pointerValue.ToString(formatProvider);

Expand Down
4 changes: 2 additions & 2 deletions SharpGen.Runtime/NativeULong.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ namespace SharpGen.Runtime;

[StructLayout(LayoutKind.Explicit)]
public readonly struct NativeULong : IEquatable<NativeULong>, IComparable<NativeULong>, IComparable
#if NET5_0
#if NET5_0_OR_GREATER
, IFormattable
#endif
{
Expand Down Expand Up @@ -62,7 +62,7 @@ public NativeULong(UIntPtr value)
public override string ToString() =>
UseInt ? _intValue.ToString() : _pointerValue.ToString();

#if NET5_0
#if NET5_0_OR_GREATER
public string ToString(string format) =>
UseInt ? _intValue.ToString(format) : _pointerValue.ToString(format);

Expand Down
10 changes: 9 additions & 1 deletion SharpGen.Runtime/ShadowAttribute.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

using System;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Reflection;
using System.Runtime.CompilerServices;

Expand All @@ -34,13 +35,20 @@ public sealed class ShadowAttribute : Attribute
/// <summary>
/// Type of the associated shadow
/// </summary>
#if NET5_0_OR_GREATER
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)]
#endif
public Type Type { get; }

/// <summary>
/// Initializes a new instance of <see cref="ShadowAttribute"/> class.
/// </summary>
/// <param name="holder">Type of the associated shadow</param>
public ShadowAttribute(Type holder)
public ShadowAttribute(
#if NET5_0_OR_GREATER
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)]
#endif
Type holder)
{
Type = holder ?? throw new ArgumentNullException(nameof(holder));

Expand Down
5 changes: 3 additions & 2 deletions SharpGen.Runtime/SharpGen.Runtime.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@

<PropertyGroup>
<!--
net5.0 for function pointers codegen and Native(U)Long API surface
net6.0 for full assembly trimming
net5.0 for function pointers codegen and Native(U)Long API surface and partial assembly trimming
netcoreapp3.0 for smaller [empty] dependency tree (w/o System.Runtime.CompilerServices.Unsafe)
netstandard2.1 + netcoreapp2.1 for smaller dependency tree (w/o System.Memory)
netstandard2.1 is .NET Core 3.0, but System.Memory is already inbox since 2.1
Expand All @@ -15,7 +16,7 @@
net45 for smaller dependency tree for all .NET Framework versions
netstandard1.3 is the lowest supported version (except .NET Framework)
-->
<TargetFrameworks>net5.0;netcoreapp3.0;netstandard2.1;netcoreapp2.1;netstandard2.0;net471;net46;net45;netstandard1.3</TargetFrameworks>
<TargetFrameworks>net6.0;net5.0;netcoreapp3.0;netstandard2.1;netcoreapp2.1;netstandard2.0;net471;net46;net45;netstandard1.3</TargetFrameworks>
<Description>Support classes for code generated by SharpGen.</Description>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<CheckEolTargetFramework>false</CheckEolTargetFramework>
Expand Down
Loading