Comment une DLL C ++ Windows peut-elle être fusionnée dans un fichier exe d'application C #?

StackOverflow https://stackoverflow.com/questions/72264

  •  09-06-2019
  •  | 
  •  

Question

J'ai un programme Windows C # qui utilise une DLL C ++ pour les E / S de données. Mon objectif est de déployer l'application en tant que fichier EXE unique.

Quelles sont les étapes pour créer un tel exécutable?

Était-ce utile?

La solution

Déploiement d'assemblages uniques de code géré et non géré Dimanche 4 février 2007

Les développeurs .NET adorent le déploiement XCOPY. Et ils aiment les composants à assemblage unique. Au moins, je me sens toujours un peu mal à l'aise si je dois utiliser un composant et me rappeler une liste de fichiers à inclure également dans l'assembly principal de ce composant. Alors, récemment, lorsque j'ai eu à développer un composant de code managé et à le compléter avec du code non managé à partir d'une DLL C (merci à Marcus Heege de m'avoir aidé à cela!), J'ai réfléchi au moyen de faciliter le déploiement des deux DLL. . S'il ne s'agissait que de deux assemblages, j'aurais pu utiliser ILmerge pour les regrouper dans un seul fichier. Mais cela ne fonctionne pas pour les composants de code mélangés avec des DLL gérées et non gérées.

Voici donc ce que j'ai proposé comme solution:

J'inclus les DLL que je souhaite déployer avec l'assembly principal de mon composant sous forme de ressources incorporées. Ensuite, j'ai configuré un constructeur de classe pour extraire ces DLL comme ci-dessous. Le ctor de classe est appelé une seule fois dans chaque domaine d’AppDom, c’est donc une surcharge négligeable, je pense.

namespace MyLib
{
    public class MyClass
    {
        static MyClass()
        {
            ResourceExtractor.ExtractResourceToFile("MyLib.ManagedService.dll", "managedservice.dll");
            ResourceExtractor.ExtractResourceToFile("MyLib.UnmanagedService.dll", "unmanagedservice.dll");
        }

        ...

Dans cet exemple, j'ai inclus deux DLL en tant que ressources, l'une étant une DLL de code non géré et l'autre une DLL de code géré (à des fins de démonstration), pour montrer comment cette technique fonctionne pour les deux types de code.

Le code permettant d'extraire les DLL dans leurs propres fichiers est simple:

public static class ResourceExtractor
{
    public static void ExtractResourceToFile(string resourceName, string filename)
    {
        if (!System.IO.File.Exists(filename))
            using (System.IO.Stream s = System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName))
                using (System.IO.FileStream fs = new System.IO.FileStream(filename, System.IO.FileMode.Create))
                {
                    byte[] b = new byte[s.Length];
                    s.Read(b, 0, b.Length);
                    fs.Write(b, 0, b.Length);
                }
    }
}

Travailler avec un assemblage de code géré comme celui-ci est identique, comme d'habitude. Vous y faites référence (ici: ManagedService.dll) dans le projet principal de votre composant (ici: MyLib), mais définissez la propriété Copy Local sur false. De plus, vous créez un lien dans l'assemblage en tant qu'élément existant et définissez l'action de génération sur une ressource incorporée.

Pour le code non géré (ici: UnmanagedService.dll), il vous suffit de créer un lien dans la DLL en tant qu'élément existant et de définir l'action de génération sur une ressource incorporée. Pour accéder à ses fonctions, utilisez l’attribut DllImport comme d’habitude, par exemple.

[DllImport("unmanagedservice.dll")] public extern static int Add(int a, int b);

C'est ça! Dès que vous créez la première instance de la classe avec le ctor statique, les DLL incorporées sont extraites dans des fichiers qui leur sont propres et sont prêtes à être utilisées comme si vous les aviez déployées en tant que fichiers séparés. Tant que vous avez les autorisations d'écriture pour le répertoire d'exécution, cela devrait fonctionner correctement pour vous. Au moins pour le code prototypique, je pense que cette méthode de déploiement d’assemblage unique est très pratique.

Profitez!

http://weblogs.asp.net/ralfw/archive/2007/02/04/single-assembly-deployment-of-managed-and-unmanaged-code.aspx

Autres conseils

Essayez boxedapp ; il permet de charger toutes les DLL de la mémoire. En outre, il semble que vous puissiez même intégrer le runtime .net. C'est bien de créer des applications vraiment autonomes ...

Utilisez le Fody.Costura nuget

.
  1. Ouvrez votre solution - > Projet - > Gérer les paquets Nuget
  2. Recherchez Fody.Costura
  3. Compilez votre projet .

C'est tout!

  

Source:    http://www.manuelmeyer.net/2016 / 01 / assemblages-de-fusion-net-power-10 /

Avez-vous essayé ILMerge? http://research.microsoft.com/~mbarnett/ILMerge.aspx

  

ILMerge est un utilitaire qui peut être utilisé pour fusionner plusieurs assemblys .NET en un seul assemblage. Il est disponible gratuitement à partir de l’outil Tools & amp; Page Utilitaires du Centre de développement Microsoft .NET Framework.

Si vous construisez la DLL C ++ avec l'indicateur / clr (tout ou partiellement C ++ / CLI), cela devrait alors fonctionner:

ilmerge /out:Composite.exe MyMainApp.exe Utility.dll

Toutefois, cela ne fonctionnera pas avec une DLL Windows (native) ordinaire (native).

Faites un clic droit sur votre projet dans Visual Studio, choisissez Propriétés du projet - > Ressources - > Ajouter une ressource - > Ajouter un fichier existant… Et ajoutez le code ci-dessous à votre App.xaml.cs ou équivalent.

public App()
{
    AppDomain.CurrentDomain.AssemblyResolve +=new ResolveEventHandler(CurrentDomain_AssemblyResolve);
}

System.Reflection.Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
    string dllName = args.Name.Contains(',') ? args.Name.Substring(0, args.Name.IndexOf(',')) : args.Name.Replace(".dll","");

    dllName = dllName.Replace(".", "_");

    if (dllName.EndsWith("_resources")) return null;

    System.Resources.ResourceManager rm = new System.Resources.ResourceManager(GetType().Namespace + ".Properties.Resources", System.Reflection.Assembly.GetExecutingAssembly());

    byte[] bytes = (byte[])rm.GetObject(dllName);

    return System.Reflection.Assembly.Load(bytes);
}

Voici mon article de blog original: http://codeblog.larsholm.net/ 2011/06 / embed-dlls-facilement-dans-un-assemblage-net /

Thinstall est une solution. Pour une application Windows native, je vous suggérerais d'incorporer la DLL en tant qu'objet ressource binaire, puis de l'extraire au moment de l'exécution avant que vous n'en ayez besoin.

Smart Assembly peut faire cela, et plus encore. Si votre dll a un code non managé, il ne vous laissera pas fusionner les dll avec un seul assemblage, mais il peut intégrer les dépendances requises en tant que ressources pour votre exe principal. Son revers, ce n’est pas gratuit.

Vous pouvez le faire manuellement en incorporant des dll à vos ressources, puis en faisant appel à Assembly ResolveHandler d'AppDomain. En ce qui concerne les dll en mode mixte, j’ai trouvé que nombre des variantes et des saveurs de l’approche ResolveHandler ne fonctionnaient pas pour moi (toutes les méthodes qui lisent les octets dll en mémoire et les lisent). Ils ont tous travaillé pour les dll gérés. Voici ce qui a fonctionné pour moi:

static void Main()
{
    AppDomain.CurrentDomain.AssemblyResolve += (sender, args) =>
    {
        string assemblyName = new AssemblyName(args.Name).Name;
        if (assemblyName.EndsWith(".resources"))
            return null;

        string dllName = assemblyName + ".dll";
        string dllFullPath = Path.Combine(GetMyApplicationSpecificPath(), dllName);

        using (Stream s = Assembly.GetEntryAssembly().GetManifestResourceStream(typeof(Program).Namespace + ".Resources." + dllName))
        {
            byte[] data = new byte[stream.Length];
            s.Read(data, 0, data.Length);

            //or just byte[] data = new BinaryReader(s).ReadBytes((int)s.Length);

            File.WriteAllBytes(dllFullPath, data);
        }

        return Assembly.LoadFrom(dllFullPath);
    };
}

La clé ici est d’écrire les octets dans un fichier et de les charger à partir de son emplacement. Pour éviter les problèmes liés aux œufs et à la poule, vous devez vous assurer de déclarer le gestionnaire avant d'accéder à l'assemblage et de ne pas accéder aux membres d'assemblage (ni instancier quoi que ce soit qui concerne l'assemblage) à l'intérieur de la partie de chargement (résolution de l'assemblage). Veillez également à ce que GetMyApplicationSpecificPath () ne soit pas un répertoire temporaire, car les fichiers temporaires pourraient être effacés par d’autres programmes ou par vous-même (il ne sera pas supprimé pendant que votre programme accède à la dll, mais au moins c'est une nuisance. AppData est bien situé). Notez également que vous devez écrire les octets à chaque fois, vous ne pouvez pas charger depuis un emplacement simplement parce que la dll y réside déjà.

Si l'assembly n'est pas entièrement géré, vous pouvez voir ceci lien ou ceci comment charger ces dlls.

PostBuild à partir de Xenocode peut regrouper les fichiers gérés en un seul.

.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top