Skip to content

Latest commit

 

History

History
84 lines (64 loc) · 8 KB

ISSUES.mkd

File metadata and controls

84 lines (64 loc) · 8 KB

Known Issues with Using Native AOT for Plugin Development

Windows Forms

A modern .NET port of Windows Forms has been available for some time. The fact that it only runs on Windows is a legacy of the original Framework version, which is tightly coupled with older Windows technologies like the COM interface.

To be a candidate for Native AOT, a library must be "trimmable", which in turn depends on avoiding dynamic type resolution, or reflection, as much as possible. Another obstacle to trimming is COM marshalling, which Windows Forms are "heavily reliant" upon.1

Microsoft's documentation suggests COM wrappers as a strategy to provide the static type guarantees that COM marshalling ordinarily precludes. Third-party attempts to bring trimmable COM marshalling to Windows Forms have already appeared, but support is still lacking for a long-term-support framework (currently .NET 8). Fortunately, it looks like Microsoft intends to eventually refactor Windows Forms for Native AOT.

To make this technical discussion more concrete (and, hopefully, to invite contributions), this repository includes a broken demo project using Windows Forms. A Native AOT build should complete successfully, but with several warnings from the IL compiler ("ILC"), e.g.,

Publishing a WinForms project with Native AOT

C:\git\Npp.DotNet.Plugin>dotnet publish examples\gui -r win-x64 -f net9.0-windows -c Release
  npp.dotnet.plugin net9.0-windows succeeded (5.3s) → lib\bin\Release\net9.0-windows\win-x64\npp.dotnet.plugin.dll
  Npp.DotNet.Plugin.Gui.Demo net9.0-windows succeeded with 5 warning(s) (41.5s) → examples\gui\bin\Release\net9.0-windows\win-x64\publish\
    C:\Users\Admin\.nuget\packages\microsoft.windowsdesktop.app.runtime.win-x64\9.0.0\runtimes\win-x64\lib\net9.0\System.Windows.Forms.Primitives.dll : warning IL3053: Assembly 'System.Windows.Forms.Primitives' produced AOT analysis warnings.
    ILC : warning IL3000: System.Windows.Forms.ThreadExceptionDialog.ThreadExceptionDialog(Exception): 'System.Reflection.Assembly.Location.get' always returns an empty string for assemblies embedded in a single-file app. If the path to the app directory is needed, consider calling 'System.AppContext.BaseDirectory'.
    C:\Users\Admin\.nuget\packages\microsoft.windowsdesktop.app.runtime.win-x64\9.0.0\runtimes\win-x64\lib\net9.0\System.Windows.Forms.dll : warning IL3053: Assembly 'System.Windows.Forms' produced AOT analysis warnings.
    ILC : warning IL3000: System.Windows.Forms.Control.ControlVersionInfo.OwnerIsInMemoryAssembly.get: 'System.Reflection.Assembly.Location.get' always returns an empty string for assemblies embedded in a single-file app. If the path to the app directory is needed, consider calling 'System.AppContext.BaseDirectory'.
    C:\Users\Admin\.nuget\packages\microsoft.windowsdesktop.app.runtime.win-x64\9.0.0\runtimes\win-x64\lib\net9.0\System.Formats.Nrbf.dll : warning IL3053: Assembly 'System.Formats.Nrbf' produced AOT analysis warnings.

Build succeeded with 5 warning(s) in 47.5s

Publishing a WinForms project with Native AOT (net8.0-windows)

C:\git\Npp.DotNet.Plugin>dotnet publish examples\gui -r win-x64 -f net8.0-windows -c Release
MSBuild version 17.9.6+a4ecab324 for .NET
  Determining projects to restore...
  All projects are up-to-date for restore.
  Npp.DotNet.Plugin -> C:\git\npp.dotnet.plugin\lib\bin\Release\net8.0-windows\Npp.DotNet.Plugin.dll
  Npp.DotNet.Plugin.Gui.Demo -> C:\git\npp.dotnet.plugin\examples\gui\bin\Release\net8.0-windows\win-x64\Npp.DotNet.Plugin.Gui.Demo.dll
  Optimizing assemblies for size may change the behavior of the app. Be sure to test after publishing. See: https://aka.ms/dotnet-illink
  Generating native code
  ILC: Method '[PresentationFramework]System.Windows.Documents.MsSpellCheckLib.RCW+SpellCheckerFactoryCoClass..ctor()' will always throw because: Invalid IL or CLR metadata in 'Void SpellCheckerFactoryCoClass..ctor()'
  ILC: Method '[PresentationFramework]System.Windows.Documents.MsSpellCheckLib.RCW+SpellCheckerFactoryCoClass.UnregisterUserDictionary(string,string)' will always throw because: Invalid
  IL or CLR metadata in 'Void SpellCheckerFactoryCoClass.UnregisterUserDictionary(System.String, System.String)'
  ILC: Method '[PresentationFramework]System.Windows.Documents.MsSpellCheckLib.RCW+SpellCheckerFactoryCoClass.RegisterUserDictionary(string,string)' will always throw because: Invalid IL
   or CLR metadata in 'Void SpellCheckerFactoryCoClass.RegisterUserDictionary(System.String, System.String)'
  ILC: Method '[PresentationFramework]System.Windows.Documents.MsSpellCheckLib.RCW+SpellCheckerFactoryCoClass.CreateSpellChecker(string)' will always throw because: Invalid IL or CLR met
  adata in 'ISpellChecker SpellCheckerFactoryCoClass.CreateSpellChecker(System.String)'
  ILC: Method '[WindowsBase]MS.Internal.Security.AttachmentService+AttachmentServices..ctor()' will always throw because: Invalid IL or CLR metadata in 'Void AttachmentServices..ctor()'
  ILC: Method '[PresentationCore]MS.Internal.AppModel.CustomCredentialPolicy+InternetSecurityManager..ctor()' will always throw because: Invalid IL or CLR metadata in 'Void InternetSecur
  ityManager..ctor()'
  ILC: Method '[System.DirectoryServices]System.DirectoryServices.UnsafeNativeMethods+PropertyEntry..ctor()' will always throw because: Invalid IL or CLR metadata in 'Void PropertyEntry.
  .ctor()'
  ILC: Method '[System.DirectoryServices]System.DirectoryServices.UnsafeNativeMethods+PropertyValue..ctor()' will always throw because: Invalid IL or CLR metadata in 'Void PropertyValue.
  .ctor()'
     Creating library bin\Release\net8.0-windows\win-x64\native\Npp.DotNet.Plugin.Gui.Demo.lib and object bin\Release\net8.0-windows\win-x64\native\Npp.DotNet.Plugin.Gui.Demo.exp
  Npp.DotNet.Plugin.Gui.Demo -> C:\git\npp.dotnet.plugin\examples\gui\bin\Release\net8.0-windows\win-x64\publish\

The warnings are significant. A module that is not properly trimmed is basically a .NET assembly. If placed in the plugin path, it may throw an unhandled exception at any time, crashing Notepad++.

Lack of AOT-compatible third-party .NET libraries

Many .NET plugins for Notepad++ depend on libraries. The IL compiler has no fault tolerance for .NET assemblies intended to run on .NET Framework, and each dependency increases the chances of a build failure. The status of third-party libraries compatible with modern .NET is completely unknown, as no .NET plugin has ever been successfully ported to a recent framework. Also keep in mind that simply targeting modern .NET does not guarantee AOT compatibility. The particular requirements for trimming compatibility may not be achievable for some libraries.

Bulky DLLs

Native AOT generates self-contained applications. Even after being trimmed, the remaining portion of the .NET runtime required to execute the app will be at least a few megabytes in size, and this will be statically linked with the binary. That's a substantial difference from a typical .NET Framework assembly, which usually weighs in at less than 1MB, with all of its runtime code residing in core system libraries.

Footnotes

  1. https://learn.microsoft.com/dotnet/core/deploying/trimming/incompatibilities#windows-forms