Building WinForms with Native AOT

2 minute read

Native AOT is incredible, we already know that, but despite microsoft not providing support for WinForms and WPF, they have already said that this is perfectly possible, although easier in Winforms than WPF, they just aren’t in the plans (they still experimented with WinForms , which is much easier, you can check it out here ). These last few weeks I’ve been working on some projects with Native AOT and this lack of support for visual applications really bothered me, because I’m really amazed with the benefits of a language compiled in C#, but ok, life goes on.

Why is WinForms easier than WPF?

If you checked out the improvements made to WinForms in .NET 7, you noticed that they already experimented with WinForms, but didn’t mention testing with WPF, this is because WPF uses a lot more reflection, making it much more difficult and laborious to get first working results. In .NET 5, selected Windows Forms built-in COM interops have been replaced with ComWrappers, so built-in COM is completely disabled in trimming/Native AOT scenarios

Is it really possible to compile WinForms with Native AOT?

Yes, but with caveats. Officially it is not supported, but microsoft itself mentions the efforts of @kant2002, who made available the WinFormsComInterop library, which allows us to compile Native AOT. Kant claims that over time this library will die, as official support for WinForms is added (I sincerely hope it happens soon). Anyway, it’s still much better than using a beta build of Avalonia in production, which is what I’m doing with some projects. Finally, you can use Native AOT + WinForms, but there are still a lot of problems during development that you will have to solve on your own for now, but you can already do a lot with it.

Step by step

With your WinForms .NET 7 project already created:

  • Add the WinFormsComInterop package through Nuget, or run the command dotnet add package WinFormsComInterop

  • In the Program.cs file, add ComWrappers.RegisterForMarshalling(WinFormsComInterop.WinFormsComWrappers.Instance); at your program startup. It will look like this:

using System.Runtime.InteropServices;

namespace WinFormsAOT_example
{
    internal static class Program
    {
        [STAThread]
        static void Main()
        {
            ComWrappers.RegisterForMarshalling(WinFormsComInterop.WinFormsComWrappers.Instance);
            ApplicationConfiguration.Initialize();
            Application.Run(new Form1());
        }
    }
}
  • Now enable Native AOT in your project by adding <PublishAot>true</PublishAot> in your project file;

  • By default, if you try to compile now, you will get an error saying that WinForms does not support trimming. To fix this, also add <_SuppressWinFormsTrimError>true</_SuppressWinFormsTrimError> in your project file

  • If using in a new project, your project file should look like this example:

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>WinExe</OutputType>
    <TargetFramework>net7.0-windows</TargetFramework>
    <Nullable>enable</Nullable>
    <UseWindowsForms>true</UseWindowsForms>
    <ImplicitUsings>enable</ImplicitUsings>
    <PublishAot>true</PublishAot>
    <_SuppressWinFormsTrimError>true</_SuppressWinFormsTrimError>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="WinFormsComInterop" Version="0.4.3" />
  </ItemGroup>

</Project>
  • Now your project is ready to be published with Native AOT 😄
Download the sample project here

Updated: