0

In C# .NET 8 given a pointer (IntPtr) to a native object implementing a COM-compatible interface and a C# interface definition, how do I convert the pointer to an object implementing such interface without using built-in COM to enable trimming?

Background:

I have a small C# app (.NET 8) which uses a COM library via autogenerated bindings from tlb. I would like to publish a standalone exe and use .NET's trimming option <PublishTrimmed> to make the exe's size reasonable.

The .NET built-in com interop does not support trimming. I have found a subset of dlls to mark not trimmable to make the app run. However, that still generates a lot of warnings and is I believe technically unsupported by .NET and can break in later .NET versions.

The COM DLL doesn't actually require full COM, it just uses COM-compatible API. All I need is to call a P/Invoke method which returns a pointer to a COM-like object, which matches the autogenerated tlb interface. How would I convert that pointer to an object implementing a particular C# COM-compatible interface using only features supported by trimming?

// auto generated from tlb
[ComImport]
[Guid(<guid>)]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface ISomeInterface
{
    [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
    void method([In][MarshalAs(UnmanagedType.LPWStr)] string input, out int pbData);
    ...
}

// my (simplified) current code using built in com interop
void GetInstance([MarshalAs(UnmanagedType.Interface)] out object createdObject);

GetInstance(out object comObject);
return comObject as ISomeInterface ?? throw new InvalidOperationException("Failed to create ISomeInterface instance.");
2
  • 1
    To simplify, there are only 2 ways to define COM interface in .NET Core (speaking only version 8+): 1) use ComImport/InterfaceType which uses built-in interop and doesn't support trimming/AOT or 2) use GeneratedComInterface+DisableRuntimeMarshalling which uses the new source generator. That's about it. You can't have trimming/AOT and keep old auto-generated code from a TLB. Commented Feb 21 at 18:24
  • 1
    So what you must do is take your ISomeInterface interface and follow this learn.microsoft.com/en-us/dotnet/standard/native-interop/… to convert it to the new GeneratedComInterface way manually. AFAIK there's currently to TLB to GeneratedComInterface tool available. This "dscom" tool is able to generate TLB for .NET Core with built-in marshaling but it looks they won't go further github.com/dspace-group/dscom/issues/212 Commented Feb 21 at 18:24

1 Answer 1

1

Simon Mourier's comments is the answer I used. I have decompiled the generated tlb dll back into C# using ILSpy . Then pseudo-manually and with help of AI to speed it up I converted attributes on the interfaces to using GeneratedComInterface instead of ComImport. Fortunately, the COM interface I am using is relatively basic, so this wasn't that difficult with no custom marshalling required.

Simon's comment provides a link with documentation for the basic cases I needed: https://learn.microsoft.com/en-us/dotnet/standard/native-interop/comwrappers-source-generation

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.