An open API service indexing awesome lists of open source software.

https://github.com/abdes/winui-override-main

A WinUI 3 visual studio solution for an application that uses a custom `Main` entry point instead of the default XAML entry point.
https://github.com/abdes/winui-override-main

Last synced: about 1 month ago
JSON representation

A WinUI 3 visual studio solution for an application that uses a custom `Main` entry point instead of the default XAML entry point.

Awesome Lists containing this project

README

          

# Override `Main` in a WinUI Application

I was writing a WinUI 3 application that uses the [Entity
Framework](https://learn.microsoft.com/en-us/ef/) and the [Microsoft Hosting
Extensions](https://learn.microsoft.com/en-us/dotnet/api/microsoft.extensions.hosting?view=dotnet-plat-ext-7.0)
for IoC.

My migrations were not working. After a lot of troubleshooting I figured out
that the `EF` migrations tool has some specific assumptions on the order of
initializing the `Host`, the `Services` and the `Application` itself. Such fine
grained control is not possible using the default generated XAML entry point.

➡ How to properly override the default generated XAML entry point?

## The default generated `Main` entry point

If we check the executable for the application we can see that the `Main` entry
point is actually in a class called `Program`. That class is generated by the
XAML compiler along with the `App` class. If we take a look in the `obj` folder
of the `App` project, there is a file named `App.g.i.cs` which contains some
partial code generated for the App class but also code that is conditionally
included based on the presence of the `DISABLE_XAML_GENERATED_MAIN` compilation
constant, defining a new class called `Program` with the `Main` entry point
definition.

```csharp
#if !DISABLE_XAML_GENERATED_MAIN
///
/// Program class
///
public static class Program
{
[global::System.Runtime.InteropServices.DllImport("Microsoft.ui.xaml.dll")]
private static extern void XamlCheckProcessRequirements();

[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.UI.Xaml.Markup.Compiler"," 3.0.0.2309")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.STAThreadAttribute]
static void Main(string[] args)
{
XamlCheckProcessRequirements();

global::WinRT.ComWrappersSupport.InitializeComWrappers();
global::Microsoft.UI.Xaml.Application.Start((p) => {
var context = new global::Microsoft.UI.Dispatching.DispatcherQueueSynchronizationContext(global::Microsoft.UI.Dispatching.DispatcherQueue.GetForCurrentThread());
global::System.Threading.SynchronizationContext.SetSynchronizationContext(context);
new App();
});
}
}
#endif
```

## Using our own `Main` entry point

The easiest way to achieve our goal is obviously to define the
DISABLE_XAML_GENERATED_MAIN constant, and include your own `Program.cs`.

The first change to make is to `App.csproj` project definition file.

```xml
+
+ true
+ DISABLE_XAML_GENERATED_MAIN
+ App.Program
```

We define the `DISABLE_XAML_GENERATED_MAIN` compile time constant and provide
our own `Program.cs`. The majority of the [`Program.cs`](App/Program.cs)
content is copied from the default one, which will ensure that the proper
initialization and checks are made as if we were using the default entry point.
Any additional pre- or post- initialization work needs to be placed
appropriately.

**ℹ NOTE 1:**
> `AllowUnsafeBlocks` is not really needed for the custom entry point but is
> required to use `LibraryImport` which is preferred to `DLLImport`.

**ℹ NOTE 2:**
> In the recent versions of the `WindowsAppSDK`, both
> `XamlCheckProcessRequirements()` and `InitializeComWrappers()` don't do
> anything. It is better however to keep them for maximum compatibility as they
> are still there in the default generated entry point.