← accueil

WinForms multiplateforme

Ce que signifie exécuter du code Windows Forms sous macOS et Linux, ce que cela coûte, et comment Majorsilence.Forms s'y prend.

Cette page est une traduction. En cas de divergence, la version anglaise fait foi. English

Windows Forms est réservé à Windows, et l’a toujours été. System.Windows.Forms est une enveloppe managée au-dessus des classes de fenêtres Win32 et de GDI+ — des HWND, WM_PAINT, user32.dll. .NET lui-même fonctionne partout, mais cet assembly n’est livré que dans le runtime Windows Desktop : une application WinForms ne peut donc ni être compilée ni être lancée sous macOS ou Linux. C’est là tout le problème, et c’est pourquoi « rendre notre application WinForms multiplateforme » a historiquement signifié « la réécrire ».

Majorsilence.Forms prend l’autre chemin : réimplémenter le modèle de programmation WinForms sur un moteur de rendu multiplateforme. Mêmes noms de classes, mêmes propriétés, mêmes événements, même code généré par le concepteur — mais rien en dessous n’est du Win32.

using Majorsilence.Forms;   // à la place de System.Windows.Forms

public class MainForm : Form
{
    public MainForm ()
    {
        var button = new Button { Text = "Click me", Location = new Point (12, 12) };
        button.Click += (s, e) => MessageBox.Show ("Hello from Linux.");
        Controls.Add (button);
    }
}

Ce fichier compile et s’exécute sous Windows, macOS et Linux à partir d’une seule compilation net10.0 (ou net8.0). Pas de TFM -windows, pas de runtime Windows Desktop, pas de Wine. La bibliothèque de base est aussi livrée en netstandard2.0, ce qui permet à une application .NET Framework 4.8 sous Windows de l’héberger elle aussi.

Comment fonctionne réellement une couche de compatibilité WinForms

Il existe trois approches pour porter du code WinForms sur une autre plateforme, et elles se comportent très différemment :

Approche Ce que c’est Compromis
Émulation (Wine, l’ancien System.Windows.Forms de Mono) Réimplémenter Win32/GDI+ sous l’assembly WinForms non modifié Zéro changement de code source, mais vous héritez d’une énorme surface Win32, d’un comportement non natif, et d’un support qui s’arrête dès que votre application touche quelque chose de non implémenté
Réécriture (WPF, .NET MAUI, Avalonia, le web) Réexprimer l’interface dans un autre paradigme Un résultat réellement moderne, au prix de la reconstruction de chaque écran et de la reformation de l’équipe
Réimplémentation compatible au niveau de l’API (Majorsilence.Forms) Reconstruire l’API WinForms sur un moteur de rendu portable Compatibilité au niveau du code source moyennant un changement mécanique de namespace ; vous renoncez aux portes de sortie Win32 comme Control.Handle et WndProc

Majorsilence.Forms est la troisième. Chaque contrôle est dessiné par le framework lui-même avec SkiaSharp — le même moteur 2D accéléré par le GPU qui se trouve derrière Chrome et Flutter — si bien qu’un Button a exactement le même aspect et le même comportement sur les trois bureaux, parce que c’est littéralement le même code de dessin sur les trois.

L’architecture en un schéma

Votre application (formulaires, contrôles, fichiers Designer — le modèle WinForms que vous connaissez) │ Majorsilence.Forms (contrôles + API compatible WinForms, dessinés avec SkiaSharp) │ Backend hôte interchangeable ├─ Avalonia → Windows · macOS · Linux (par défaut) · aussi Android · iOS · navigateur ├─ Uno → bureau · iOS · Android · WebAssembly ├─ GTK 4 → vraie fenêtre GTK, Linux d'abord (gir.core), aussi Windows/macOS avec le runtime GTK ├─ Terminal → le formulaire dessiné dans un terminal (graphiques Kitty, Sixel ou blocs Unicode) ├─ WinForms → pont de migration Windows uniquement : intégrez dans une application WinForms existante, portez par étapes ├─ WPF → pont de migration Windows uniquement, même principe, pour une application WPF existante └─ Headless → rendu hors écran pour les tests / la CI

L’assembly de base Majorsilence.Forms ne référence aucune boîte à outils de fenêtrage — uniquement SkiaSharp. Le seul travail d’un backend est de créer une fenêtre native (ou un terminal, ou rien du tout), de faire tourner une boucle de messages, de transmettre les entrées et de présenter une surface Skia. Cette couture (la frontière backend) est la raison pour laquelle le même binaire d’application peut viser Avalonia sur le bureau aujourd’hui et GTK 4, Uno ou WebAssembly demain — et pour laquelle une application Windows peut héberger exactement les mêmes contrôles dans ses fenêtres WinForms ou WPF existantes pendant sa migration. Voir Backends de plateforme pour les interfaces et la façon d’ajouter le vôtre.

Ce que vous obtenez sur chaque plateforme

Plateforme État Hôte
Windows Pris en charge, prêt à l’emploi Avalonia (par défaut), Uno, ou GTK 4 avec le runtime GTK installé
Windows, à l’intérieur d’une application WinForms ou WPF existante Pris en charge — migration incrémentale, un contrôle à la fois ; s’héberge aussi depuis .NET Framework 4.8 (net48) Majorsilence.Forms.WinForms / Majorsilence.Forms.Wpf
macOS (Intel et Apple Silicon) Pris en charge, prêt à l’emploi — voir WinForms sous macOS Avalonia (par défaut), Uno, ou GTK 4 via Homebrew
Linux (X11 / Wayland) Pris en charge, prêt à l’emploi — voir WinForms sous Linux Avalonia (par défaut, X11), GTK 4 (Wayland/X11 natif, vérifié sous Wayland), ou Uno
Terminal Fonctionnel, jeune — vérifié dans xterm et WezTerm Majorsilence.Forms.Terminal : le formulaire remplit le terminal, dessiné en graphiques Kitty, Sixel ou blocs Unicode
WebAssembly / navigateur Fonctionnel, jeune — essayez la galerie en ligne ; les lecteurs d’écran voient un miroir DOM ARIA de l’interface Avalonia Browser ou Uno Wasm
Android Précoce — première passe sur appareil réel effectuée (démarrage, appuis, mise à l’échelle du rendu, défilement tactile confirmés sur matériel) ; clavier, zone sûre et rotation testés unitairement seulement Avalonia Android ou Uno
iOS Précoce — la CI compile la vraie tête et la lance dans un simulateur pour un test de fumée, mais personne ne l’a encore utilisée de manière interactive Avalonia iOS ou Uno
Headless / CI Pris en charge Backend Headless, Skia hors écran

Les API réservées à Windows qu’un portage doit remplacer

Rendre les contrôles portables n’est que la moitié du travail. Une vraie application WinForms s’appuie aussi sur d’autres piles réservées à Windows, et chacune a ici sa réponse multiplateforme :

Ce que cela coûte

Être honnête sur le compromis est plus utile qu’une liste de fonctionnalités :

Pour aller plus loin