Est-il possible d'incorporer une DLL préexistante dans un exécutable C # compilé (afin que vous n'ayez qu'un seul fichier à distribuer)? Si c'est possible, comment procéder?
Normalement, je suis cool de simplement laisser les DLL à l'extérieur et d'avoir le programme d'installation gérer tout, mais il y a quelques personnes au travail qui m'ont demandé cela et je ne sais vraiment pas.
Réponses:
Je recommande fortement d'utiliser Costura.Fody - de loin la manière la meilleure et la plus simple d'incorporer des ressources dans votre assemblage. Il est disponible sous forme de package NuGet.
Après l'avoir ajouté au projet, il incorporera automatiquement toutes les références copiées dans le répertoire de sortie dans votre assembly principal . Vous voudrez peut-être nettoyer les fichiers incorporés en ajoutant une cible à votre projet:
Vous pourrez également spécifier s'il faut inclure les pdb, exclure certains assemblages ou extraire les assemblages à la volée. Pour autant que je sache, les assemblys non gérés sont également pris en charge.
Mise à jour
Actuellement, certaines personnes essaient d'ajouter la prise en charge de DNX .
Update 2
Pour la dernière version de Fody, vous aurez besoin d'avoir MSBuild 16 (donc Visual Studio 2019). Fody version 4.2.1 fera MSBuild 15. (référence: Fody n'est pris en charge que sur MSBuild 16 et supérieur. Version actuelle: 15 )
la source
Faites simplement un clic droit sur votre projet dans Visual Studio, choisissez Propriétés du projet -> Ressources -> Ajouter une ressource -> Ajouter un fichier existant… Et incluez le code ci-dessous dans votre App.xaml.cs ou équivalent.
Voici mon article de blog original: http://codeblog.larsholm.net/2011/06/embed-dlls-easily-in-a-net-assembly/
la source
bytes
est nul, et si c'est le cas, renvoyez-y null. Il est possible que la DLL ne soit pas dans les ressources, après tout. Deux: cela ne fonctionne que si cette classe elle-même n'a pas de "utilisation" pour quoi que ce soit de cet assembly. Pour les outils de ligne de commande, j'ai dû déplacer mon code de programme réel vers un nouveau fichier et créer un petit nouveau programme principal qui fait juste cela, puis appelle le principal d'origine dans l'ancienne classe..dll
nom contient des tirets (ietwenty-two.dll
), ceux-ci seront également remplacés par un trait de soulignement (ietwenty_two.dll
). Vous pouvez changer cette ligne de code en ceci:dllName = dllName.Replace(".", "_").Replace("-", "_");
S'ils sont réellement des assemblys gérés, vous pouvez utiliser ILMerge . Pour les DLL natives, vous aurez un peu plus de travail à faire.
Voir aussi: Comment une DLL Windows C ++ peut-elle être fusionnée dans un exe d'application C #?
la source
C++
sur le lien. ILMerge fonctionne également très facilement pour VB NET. Voir ici https://github.com/dotnet/ILMerge . Merci @ Shog9Oui, il est possible de fusionner des exécutables .NET avec des bibliothèques. Il existe plusieurs outils disponibles pour effectuer le travail:
De plus, cela peut être combiné avec le Mono Linker , qui supprime le code inutilisé et réduit donc l'assemblage résultant.
Une autre possibilité consiste à utiliser .NETZ , qui permet non seulement de compresser un assemblage, mais peut également compresser les DLL directement dans l'exe. La différence avec les solutions mentionnées ci-dessus est que .NETZ ne les fusionne pas, ils restent des assemblages séparés mais sont regroupés dans un seul package.
la source
ILMerge peut combiner des assemblys en un seul assembly à condition que l'assembly ne dispose que de code managé. Vous pouvez utiliser l'application de ligne de commande ou ajouter une référence à l'exe et fusionner par programme. Pour une version GUI, il y a Eazfuscator , et aussi .Netz, tous deux gratuits. Les applications payantes incluent BoxedApp et SmartAssembly .
Si vous devez fusionner des assemblys avec du code non managé , je suggère SmartAssembly . Je n'ai jamais eu de hoquet avec SmartAssembly mais avec tous les autres. Ici, il peut intégrer les dépendances requises en tant que ressources à votre exe principal.
Vous pouvez faire tout cela manuellement sans avoir à vous inquiéter si l'assembly est géré ou en mode mixte en intégrant la DLL à vos ressources, puis en s'appuyant sur l'assembly d'AppDomain
ResolveHandler
. Il s'agit d'une solution à guichet unique en adoptant le pire des cas, à savoir les assemblys avec du code non managé.La clé ici est d'écrire les octets dans un fichier et de les charger à partir de son emplacement. Pour éviter les problèmes de poule et d'oeuf, vous devez vous assurer de déclarer le gestionnaire avant d'accéder à l'assemblage et de ne pas accéder aux membres de l'assemblage (ou instancier tout ce qui doit traiter l'assemblage) à l'intérieur de la pièce de chargement (résolution d'assemblage). Veillez également à ce qu'il
GetMyApplicationSpecificPath()
n'y ait pas de répertoire temporaire car les fichiers temporaires pourraient être effacés par d'autres programmes ou par vous-même (non pas qu'il sera supprimé pendant que votre programme accède à la DLL, mais au moins c'est une nuisance. AppData est bon emplacement). Notez également que vous devez écrire les octets à chaque fois, vous ne pouvez pas charger à partir de l'emplacement, car la DLL y réside déjà.Pour les DLL gérées, vous n'avez pas besoin d'écrire d'octets, mais de charger directement à partir de l'emplacement de la DLL, ou simplement de lire les octets et de charger l'assembly à partir de la mémoire. Comme ceci ou cela:
Si l'assembly n'est pas entièrement géré, vous pouvez voir ce lien ou ceci pour savoir comment charger de telles DLL.
la source
L' extrait de Jeffrey Richter est très bon. En bref, ajoutez les bibliothèques en tant que ressources intégrées et ajoutez un rappel avant toute autre chose. Voici une version du code (trouvée dans les commentaires de sa page) que j'ai mise au début de la méthode Main pour une application console (assurez-vous simplement que tous les appels qui utilisent les bibliothèques sont dans une méthode différente de Main).
la source
Pour développer la réponse de @ Bobby ci- dessus. Vous pouvez modifier votre .csproj pour utiliser IL-Repack pour empaqueter automatiquement tous les fichiers dans un seul assembly lors de la génération.
Install-Package ILRepack.MSBuild.Task
Voici un exemple simple qui fusionne ExampleAssemblyToMerge.dll dans la sortie de votre projet.
la source
Vous pouvez ajouter les DLL en tant que ressources intégrées, puis demander à votre programme de les décompresser dans le répertoire de l'application au démarrage (après avoir vérifié si elles s'y trouvent déjà).
Cependant, les fichiers d'installation sont si faciles à créer que je ne pense pas que cela en vaille la peine.
EDIT: Cette technique serait facile avec les assemblys .NET. Avec des DLL non .NET, ce serait beaucoup plus de travail (il faudrait trouver où décompresser les fichiers et les enregistrer, etc.).
la source
Un autre produit qui peut gérer cela avec élégance est SmartAssembly, sur SmartAssembly.com . Ce produit, en plus de fusionner toutes les dépendances dans une seule DLL, (facultativement) obscurcira votre code, supprimera les métadonnées supplémentaires pour réduire la taille du fichier résultant, et peut également réellement optimiser l'IL pour augmenter les performances d'exécution.
Il existe également une sorte de fonctionnalité de gestion / rapport d'exception globale qu'il ajoute à votre logiciel (si vous le souhaitez) qui pourrait être utile. Je crois qu'il dispose également d'une API de ligne de commande afin que vous puissiez l'intégrer à votre processus de génération.
la source
Ni l'approche ILMerge ni la gestion par Lars Holm Jensen de l'événement AssemblyResolve ne fonctionneront pour un hôte de plugin. Supposons que l'exécutable H charge l'assembly P de manière dynamique et y accède via l'interface IP définie dans un assembly séparé. Pour intégrer IP dans H , il faudra une petite modification du code de Lars:
L'astuce pour gérer les tentatives répétées pour résoudre le même assembly et renvoyer l'existant au lieu de créer une nouvelle instance.
EDIT: de peur de gâcher la sérialisation de .NET, assurez-vous de retourner null pour tous les assemblys non intégrés dans le vôtre, ce qui revient par défaut au comportement standard. Vous pouvez obtenir une liste de ces bibliothèques en:
et renvoyez simplement null si l'assembly passé n'appartient pas
IncludedAssemblies
.la source
.NET Core 3.0 prend en charge nativement la compilation en un seul .exe
La fonctionnalité est activée par l'utilisation de la propriété suivante dans votre fichier de projet (.csproj):
Cela se fait sans aucun outil externe.
Voir ma réponse à cette question pour plus de détails.
la source
Cela peut sembler simpliste, mais WinRar donne la possibilité de compresser un tas de fichiers en un exécutable auto-extractible.
Il a beaucoup d'options configurables: icône finale, extraire les fichiers vers un chemin donné, fichier à exécuter après l'extraction, logo / textes personnalisés pour la fenêtre contextuelle affichée pendant l'extraction, pas de fenêtre contextuelle du tout, texte du contrat de licence, etc.
Peut être utile dans certains cas .
la source
J'utilise le compilateur csc.exe appelé à partir d'un script .vbs.
Dans votre script xyz.cs, ajoutez les lignes suivantes après les directives (mon exemple est pour le Renci SSH):
Les balises ref, res et ico seront récupérées par le script .vbs ci-dessous pour former la commande csc.
Ajoutez ensuite l'appelant du résolveur d'assembly dans le Main:
... et ajoutez le résolveur lui-même quelque part dans la classe:
Je nomme le script vbs pour qu'il corresponde au nom du fichier .cs (par exemple, ssh.vbs recherche ssh.cs); cela rend l'exécution du script plusieurs fois beaucoup plus facile, mais si vous n'êtes pas un idiot comme moi, un script générique pourrait récupérer le fichier .cs cible à partir d'un glisser-déposer:
la source
Il est possible, mais pas si simple, de créer un assemblage hybride natif / géré en C #. Si vous utilisiez C ++ à la place, ce serait beaucoup plus facile, car le compilateur Visual C ++ peut créer des assemblages hybrides aussi facilement que toute autre chose.
À moins que vous n'ayez une exigence stricte de produire un assemblage hybride, je suis d'accord avec MusiGenesis que cela ne vaut pas vraiment la peine d'être fait avec C #. Si vous devez le faire, envisagez plutôt de passer à C ++ / CLI.
la source
Généralement, vous auriez besoin d'une forme d'outil de post-construction pour effectuer une fusion d'assemblage comme vous le décrivez. Il existe un outil gratuit appelé Eazfuscator (eazfuscator.blogspot.com/) qui est conçu pour la manipulation de bytecode qui gère également la fusion des assemblys. Vous pouvez l'ajouter dans une ligne de commande de post-génération avec Visual Studio pour fusionner vos assemblys, mais votre kilométrage variera en raison de problèmes qui surviendront dans tous les scénarios de fusion d'assemblys non classiques.
Vous pouvez également vérifier si la construction fait de l'utilité NANT a la capacité de fusionner des assemblys après la construction, mais je ne connais pas assez bien NANT pour dire si la fonctionnalité est intégrée ou non.
Il existe également de nombreux plug-ins Visual Studio qui effectueront la fusion d'assembly dans le cadre de la création de l'application.
Alternativement, si vous n'avez pas besoin que cela soit fait automatiquement, il existe un certain nombre d'outils comme ILMerge qui fusionneront les assemblys .net en un seul fichier.
Le plus gros problème que j'ai rencontré avec la fusion d'assemblys est qu'ils utilisent des espaces de noms similaires. Ou pire, référencez différentes versions de la même dll (mes problèmes étaient généralement avec les fichiers dll NUnit).
la source