Cet article est parti de la publication suivante.
Sous Windows, « si possible, on aimerait distribuer ça en un seul fichier » est une demande tout à fait courante. Pour les outils internes, les outils d’intégration avec des équipements, les postes de surveillance, les environnements hors ligne, et les sites qui veulent autant que possible éviter les installateurs, le passage en binaire unique est très séduisant.
Cependant, si l’on ne clarifie pas ce point dès le départ, la discussion finit généralement par ne plus se recouper en cours de route. En effet, ce qu’on appelle « vouloir un binaire unique » sous Windows mélange en réalité facilement quatre sujets distincts.
- On veut réduire la distribution à un seul artefact
- On veut éviter d’avoir à préinstaller les runtimes .NET ou Visual C++
- On veut que ça fonctionne simplement en le déposant, sans installateur ni droits administrateur
- On ne veut pas dépendre des différences entre versions de Windows cibles
Ces quatre points ne sont pas identiques. En pratique, c’est cette façon de voir les choses qui colle le mieux à la réalité :
On peut, dans une large mesure, ramener la distribution à un seul EXE. Mais on ne peut pas réduire à zéro la dépendance au Windows cible.
Cet article fait le point sur cette frontière, du point de vue pratique du développement d’applications Windows.
1. D’abord, la conclusion
Pour résumer d’emblée la conclusion :
- Pour un EXE de bureau ordinaire, on peut pousser le passage en binaire unique jusqu’à un niveau assez élevé
- Cependant, pouvoir tenir en un seul EXE et ne pas dépendre du Windows cible sont deux choses différentes
- Pour les extensions Shell, les services Windows, les pilotes, WebView2 et une partie de WinUI 3, le vrai sujet tend à être moins le nombre de fichiers que ce que l’on enregistre auprès de l’OS et ce que l’on présuppose de lui
- Ce qui compte le plus en pratique, c’est de décider séparément si l’on veut un binaire unique, l’absence d’installateur, ou moins de dépendances au système
Autrement dit, la ligne de partage sous Windows se dessine ainsi.
- Réduire la distribution à un seul artefact : très réalisable
- Embarquer des runtimes supplémentaires : très réalisable
- Se rapprocher d’une distribution xcopy : dépend du type d’application
- Supprimer les dépendances côté Windows cible : impossible
2. Penser « binaire unique » en quatre niveaux
2.1 Niveau A : un seul artefact de distribution
Le niveau le plus superficiel est celui-ci.
- On peut l’envoyer par e-mail en un seul fichier
- Il suffit d’en placer un seul sur une clé USB
- On ne place que
app.exeà l’emplacement de destination
C’est une question d’unité de distribution apparente. En réalité, même si l’application extrait temporairement des fichiers au démarrage, ou dépend de DLL côté OS, cette seule condition peut être satisfaite.
2.2 Niveau B : pas besoin de préinstaller le runtime du langage
Ensuite vient l’état où l’application fonctionne sans avoir besoin d’installer au préalable le runtime .NET ou le package redistribuable VC++ sur la machine cible.
- Liaison statique en C/C++
- Mode self-contained de .NET
- Mode single-file de .NET
- Native AOT de .NET
À ce niveau, la sensation de pouvoir « l’emporter tel quel » devient nettement plus forte.
2.3 Niveau C : pas besoin d’installation ni d’enregistrement
À partir d’ici, les choses se compliquent brusquement.
Un simple EXE peut fonctionner en le déposant tel quel. Mais les cas suivants sont différents.
- Extensions Shell
- Services Windows
- Schémas d’URL personnalisés et associations de fichiers
- Pilotes
- Composants chargés dans d’autres processus, comme l’Explorateur ou Office
Ce domaine ne se règle pas en se contentant de déposer un fichier. Il faut un enregistrement côté OS, ou une mise en relation avec l’hôte.
2.4 Niveau D : aucune dépendance au Windows cible
C’est impossible sous Windows.
Une application Windows s’exécute en fin de compte au-dessus des API Windows, du chargeur, du modèle de sécurité et de la pile de périphériques. Ce que le passage en binaire unique peut couvrir se limite au périmètre de responsabilité propre à l’application. On n’emporte pas l’OS lui-même avec soi.
3. Les domaines où un seul EXE est assez facilement atteignable
Même sous Windows, certaines applications se prêtent relativement bien à un seul EXE.
- Outils de bureau lancés de manière autonome
- Applications métier où l’EXE lui-même porte l’interface et le traitement
- Outils de type communication, traitement de fichiers, collecte de journaux, surveillance ou pilotage d’équipements
- Ce qui ne nécessite pas d’intégration hôte avec l’Explorateur ou Office
- Interfaces qui ne présupposent pas de runtime web
Pour ce type d’application, beaucoup d’éléments se prêtent facilement à être inclus dans l’application elle-même.
- Code propre
- Ressources
- Manifeste
- Paramètres par défaut
- Données de modèle
- Certaines bibliothèques tierces
- Le runtime du langage lui-même
De plus, même sans embarquer complètement les DLL à l’intérieur de l’EXE, la distribution app-local, qui place les DLL à côté de l’EXE, est une option tout à fait solide sous Windows. En pratique,
- un seul
app.exe - ou
app.exeaccompagné de quelques DLL adjacentes - mais sans installateur, sans droits administrateur, distribuable par xcopy
Il n’est pas rare que cette forme soit plus facile à maintenir que de tout compresser de force en un seul EXE.
4. Les dépendances à Windows qui subsistent même avec un seul EXE
Si l’on se dit « avec un seul EXE, on ne dépend plus du Windows cible », c’est là que les problèmes surviennent. En réalité, des dépendances subsistent même avec un seul EXE.
4.1 Dépendance à la version de l’OS
Chaque API Windows a sa propre version d’OS minimale supportée. Il existe aussi des différences entre x64 et Arm64. Autrement dit, même avec un seul EXE, il faut fixer dès le départ :
- L’application doit-elle fonctionner jusqu’à Windows 10 ?
- Windows 11 est-il un prérequis ?
- Doit-elle aussi fonctionner sous Windows Server ?
- Quelle(s) architecture(s) parmi x86 / x64 / Arm64 sont ciblées ?
4.2 Dépendance aux DLL système
Même si l’on pense avoir réduit l’application à un seul EXE, à l’exécution elle utilise bien entendu des composants fournis par l’OS.
kernel32.dlluser32.dlladvapi32.dll- L’infrastructure COM
- L’infrastructure de contrôle des services
Tout cela relève du périmètre de responsabilité de Windows.
4.3 Dépendance au modèle de sécurité
- UAC
- Les ACL de fichiers
- Le gestionnaire de contrôle des services
- Le Registre
- La politique de signature des pilotes
Ce genre d’éléments ne peut pas être pris en charge par l’application seule.
4.4 Dépendance à l’hôte ou au runtime
Si la conception n’est pas celle d’un EXE autonome, mais d’une application qui repose sur un hôte, les dépendances augmentent d’un coup.
- Utiliser WebView2 : le WebView2 Runtime est nécessaire
- Utiliser WinUI 3 / Windows App SDK : il faut clarifier le mode de distribution
- Créer une extension Shell : un enregistrement côté Explorateur est nécessaire
Autrement dit, il arrive souvent que le choix de l’interface ou de l’intégration devienne directement la difficulté de la distribution.
5. Un point de vue réaliste par technologie
5.1 C/C++ natif
Le C/C++ natif se situe du côté où le passage en binaire unique offre le plus de liberté. Il est possible d’opter pour la liaison statique, et un EXE autonome peut assez facilement être ramené à un seul fichier.
Cependant, plus important en pratique que de tout entasser dans un seul fichier, il y a :
- Que faire de l’UCRT et du runtime VC++
- Placer ou non les DLL tierces en app-local
- Jusqu’où restreindre le CPU / l’OS cible
5.2 .NET
.NET dispose de single-file, self-contained et Native AOT, ce qui permet de rendre l’unité de distribution apparente assez réduite.
Il faut cependant garder ces distinctions claires.
- framework-dependent : dépend du .NET présent dans l’environnement cible
- self-contained : embarque le runtime .NET
- single-file : regroupe la distribution en un seul artefact
- Native AOT : réduit encore les dépendances au démarrage, mais avec des contraintes fonctionnelles
Ce n’est pas parce que c’est du single-file que les dépendances au système diminuent. Ce qui diminue, c’est avant tout la dispersion des artefacts de distribution de l’application.
5.3 WebView2
Adopter WebView2 change complètement la difficulté du binaire unique. Le vrai sujet ici n’est pas le nombre d’EXE, mais la façon de gérer le WebView2 Runtime.
Avant même de se demander « peut-on en faire un seul EXE », il y a des questions à se poser en premier.
- Suppose-t-on que le Runtime existe déjà dans l’environnement ?
- Utilise-t-on Evergreen ?
- Embarque-t-on une Fixed Version ?
- Jusqu’où prend-on la responsabilité de la distribution hors ligne ?
5.4 WinUI 3 / Windows App SDK
WinUI 3 aussi voit ses exigences de distribution changer dès l’adoption. Le choix de la technologie d’interface devient, de fait, le choix de la méthode de distribution.
Si le binaire unique est la priorité absolue, il est souvent plus rapide de remettre d’abord en question le choix de la technologie d’interface.
6. Les domaines qui exigent fondamentalement un enregistrement et des dépendances
6.1 Extensions Shell
Une extension Shell chargée dans l’Explorateur est un objet différent d’un simple « EXE à déposer ». Ici, le sujet n’est pas le nombre de fichiers mais la façon de l’enregistrer auprès de l’Explorateur.
6.2 Services Windows
Même si l’exe du service lui-même peut tenir en un seul fichier, la distribution reste un problème à part.
- L’enregistrement auprès du SCM
- Les privilèges
- Le compte de démarrage
- Les paramètres de récupération
doivent être pris en compte. Autrement dit, pour un service, le vrai travail à approfondir n’est pas « en faire un seul EXE » mais « comment l’installer ».
6.3 Pilotes
Pour les pilotes, c’est encore plus net. Ils ne peuvent exister qu’en intégrant le fichier INF, la signature et la procédure d’installation, ce qui fait qu’ils se prêtent mal, dès le départ, au terrain du binaire unique.
7. Un tableau de décision pour la pratique
Pour un jugement rapide, ce tableau est pratique.
| Ce que l’on veut construire | Faisabilité d’un seul EXE | Ce qu’il faut d’abord examiner |
|---|---|---|
| Outil Win32 / C++ autonome | Élevée | Liaison statique, OS / architecture cible |
| Outil WinForms / WPF autonome | Élevée | Pertinence de self-contained, single-file, Native AOT |
| Application WinUI 3 / Windows App SDK | Moyenne | Mode de distribution, dépendances supplémentaires |
| Interface de bureau basée sur WebView2 | Faible à moyenne | Mode de distribution du Runtime |
| Extension clic droit ou aperçu de l’Explorateur | Faible | Enregistrement COM / Registre |
| Service Windows | Moyenne | Enregistrement SCM, privilèges, procédure de mise à jour |
| Application intégrant un pilote | Faible | INF, signature, installation |
Ce qui compte le plus dans ce tableau, c’est de comprendre que « le nombre de binaires » et « le périmètre de responsabilité de la distribution » sont deux choses différentes.
8. Ce qu’il faut décider en amont dans la conception de la distribution
Pour réussir le passage en binaire unique, il y a des points à trancher avant même l’implémentation.
8.1 Décider ce que l’on veut vraiment ramener à « un seul »
- Veut-on un seul artefact de distribution ?
- Veut-on supprimer la préinstallation du runtime ?
- Veut-on se passer d’installateur ?
- Veut-on faciliter les mises à jour hors ligne ?
La réponse à ces questions détermine la technologie à choisir.
8.2 Fixer dès le départ le Windows minimal supporté et l’architecture
Le single-file comme Native AOT sont, par nature, spécifiques à un OS et une architecture. Si l’on avance en laissant ce point flou, avec pour seule consigne « un seul fichier, coûte que coûte », on finit par se heurter à des API manquantes ou des incompatibilités de runtime.
8.3 Formaliser ce qui est embarqué et ce qui est laissé à Windows
En pratique, le simple fait de rédiger ce tableau réduit considérablement les incidents.
- Ce que l’application embarque
- L’exe principal
- Les DLL propres
- Les modèles de configuration
- Le runtime self-contained
- Ce que l’on laisse à Windows
- Les DLL système
- Les API de l’OS
- Le SCM / le Registre / l’Explorateur
- L’infrastructure des pilotes
- Ce que l’on présuppose séparément
- Le WebView2 Runtime
- Le VC++ Redistributable
- Office / Excel
- Les pilotes dédiés
8.4 Si l’on priorise le binaire unique, réduire l’intégration à l’hôte
Cela a un effet notable.
- Abandonner l’extension Shell au profit d’un EXE ordinaire
- Ne pas en faire un service, et se contenter du Planificateur de tâches ou d’un lancement explicite
- Utiliser une interface native plutôt que WebView2
- Garder COM confiné à son propre processus
En somme, plus on réduit les conceptions qui font que l’OS doit « charger » ou « enregistrer » son code, plus on se rapproche du binaire unique.
9. Résumé
Le passage en binaire unique sous Windows est réalisable dans une large mesure. Mais tout se ramène en définitive à cette phrase :
On peut faire d’une application un seul EXE. Mais on ne peut pas faire du Windows dont cette application dépend un seul EXE.
Voici cinq points à retenir en particulier.
- Pour un EXE ordinaire lancé de manière autonome, on peut pousser la distribution en un seul fichier remarquablement loin
- La liaison statique en C/C++, le single-file de .NET et Native AOT sont des options solides
- Cependant, les dépendances à la version de l’OS, à l’architecture, aux DLL système et au modèle de sécurité ne disparaissent pas
- Pour les extensions Shell, les services, les pilotes, WebView2 et une partie de WinUI 3, l’enregistrement auprès de l’OS et les runtimes supplémentaires deviennent le sujet principal
- La réussite du binaire unique se joue en clarifiant dès le départ « ce que l’on veut vraiment ramener à un seul »
Si l’on privilégie fortement le binaire unique, concevoir dès le choix des technologies dans le sens d’une réduction du couplage avec l’OS rend le succès bien plus probable.
10. Références
- Microsoft Learn, Create a single file for application deployment
- Microsoft Learn, Native AOT deployment overview
- Microsoft Learn, C runtime (CRT) and C++ standard library (STL) lib files
- Microsoft Learn, Dynamic-link library search order
- Microsoft Learn, Targeting your application for Windows
- Microsoft Learn, Creating Registration-Free COM Objects
- Microsoft Learn, Registering Shell Extension Handlers
- Microsoft Learn, CreateServiceW function
- Microsoft Learn, Overview of INF Files
- Microsoft Learn, Windows driver signing tutorial
- Microsoft Learn, Distribute your app and the WebView2 Runtime
- Microsoft Learn, Windows App SDK deployment guide for self-contained apps
</content>
Articles associés
Articles récents partageant les mêmes étiquettes, pour approfondir des sujets proches.
WebView2 est-il le bon successeur du mode IE ? — La contrainte ActiveX et une conception de migration réaliste
Un tour d'horizon de l'architecture de base de WebView2, des stratégies de distribution Evergreen et Fixed Version, du piège du dossier d...
Externalisation et développement sur mesure d'une application Windows : ce qu'il faut clarifier avant de se lancer
Avant de confier l'externalisation ou le développement sur mesure d'une application Windows, voici les points à clarifier : révision d'un...
Checklist pour gérer les processus enfants en toute sécurité dans une application Windows
Pour gérer en toute sécurité les processus enfants dans une application Windows, l'important n'est pas l'API de lancement mais la concept...
Compatibilité descendante des interfaces DLL et COM — Tableau de décision : quels changements cassent les appelants
Quels changements apportés à une DLL ou à un composant COM cassent réellement leurs appelants ? Nous détaillons les trois niveaux de comp...
Comment comprendre l'isolation des sessions Windows — Session 0, RDP et exécution simultanée de plusieurs utilisateurs
Cet article démêle le concept de « session » Windows, un sujet qui déroute régulièrement les développeurs d'applications Windows. Il expl...
Sujets associés
Ces pages replacent le sujet dans un contexte plus large de services et de décisions.
Thèmes techniques Windows
Portail des sujets sur le développement Windows, l'analyse des incidents et la valorisation des actifs existants.
Services liés à ce sujet
Cet article est directement lié aux services suivants.
Développement d'applications Windows
Pour la distribution d'une application Windows, concevoir dès le départ le passage en single-file, l'intégration du runtime, le choix d'adopter WebView2 ou WinUI, et l'opportunité de la faire fonctionner en service permet de réduire les retours en arrière.
Conseil technique et revue de conception
La demande « nous voulons un seul EXE » devient beaucoup plus facile à trancher une fois qu'on distingue l'unité de distribution, les dépendances au système, la nécessité d'un enregistrement et la responsabilité des mises à jour.
Questions fréquentes
Questions souvent posées lors d’une consultation sur le sujet de cet article.
- Peut-on distribuer une application Windows sous la forme d'un seul fichier EXE ?
- Pour un outil de bureau lancé de manière autonome, c'est possible jusqu'à un niveau assez élevé. En utilisant la liaison statique en C/C++, le mode self-contained ou single-file de .NET, ou encore Native AOT, on peut regrouper la distribution en un seul EXE. Cependant, pouvoir tenir en un seul EXE et ne pas dépendre du Windows cible sont deux choses différentes : les dépendances à la version de l'OS, à l'architecture, aux DLL système et au modèle de sécurité ne disparaissent pas.
- Le mode single-file de .NET fait-il disparaître les dépendances au système ?
- Non. Ce que le single-file réduit avant tout, c'est la dispersion des artefacts de distribution de l'application, pas les dépendances au système. Le mode framework-dependent dépend du .NET installé dans l'environnement cible, le mode self-contained embarque le runtime .NET, et Native AOT réduit encore davantage les dépendances au démarrage, mais au prix de certaines contraintes fonctionnelles. Le single-file comme Native AOT sont par nature spécifiques à un OS et une architecture, il faut donc fixer dès le départ la version minimale de Windows et l'architecture cible.
- Quels types d'applications sont difficiles à ramener à un seul EXE ?
- Les extensions Shell, les services Windows, les pilotes, les interfaces basées sur WebView2, et une partie de WinUI 3. Pour ces applications, le vrai sujet n'est pas le nombre de fichiers mais l'enregistrement auprès de l'OS et la gestion des runtimes supplémentaires. Par exemple, une extension Shell doit être enregistrée auprès de l'Explorateur, un service nécessite un enregistrement auprès du SCM ainsi qu'une conception des privilèges et du compte de démarrage, et un pilote ne peut exister qu'avec un fichier INF et une signature, si bien qu'une distribution qui se limite à « déposer le fichier » ne fonctionne pas. Pour WebView2, il faut d'abord décider du mode de distribution du WebView2 Runtime.
- Existe-t-il une meilleure méthode de distribution que de tout forcer dans un seul EXE ?
- La distribution app-local, qui place les DLL à côté de l'EXE, est une option solide. Même sous la forme d'un app.exe accompagné de quelques DLL adjacentes, si la distribution peut se faire par xcopy sans installateur ni droits administrateur, il n'est pas rare que ce soit plus facile à maintenir que de tout compresser de force en un seul EXE. L'important est de distinguer dès le départ si l'on veut un seul artefact de distribution, si l'on veut supprimer la préinstallation du runtime, ou si l'on veut se passer d'un installateur.
Profil de l’auteur
Page de présentation de l’auteur de l’article.
Go Komura
Représentant de KomuraSoft LLC
Spécialisé dans le développement de logiciels Windows, le conseil technique et l’analyse de pannes, notamment pour les systèmes existants et les incidents difficiles à reproduire.
Liens publics