Incorporation d'une dll dans une autre en tant que ressource incorporée, puis appelez-la à partir de mon code

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

  •  01-07-2019
  •  | 
  •  

Question

J'ai créé une DLL qui utilise une autre DLL tierce, mais je préférerais pouvoir la créer dans ma DLL plutôt que de devoir les conserver ensemble si possible.

Ceci est C # et .NET 3.5.

Pour ce faire, stockez la DLL tierce en tant que ressource incorporée que je place ensuite à l'emplacement approprié lors de l'exécution de la première DLL.

Au départ, j'avais prévu d'écrire du code pour placer la DLL tierce à l'emplacement spécifié par System.Reflection.Assembly.GetExecutingAssembly (). Location.ToString () moins le dernier /nameOfMyAssembly.dll . Je peux enregistrer avec succès le tiers .DLL à cet emplacement (qui finit par être

  

C: \ Documents and Settings \ myUserName \ Local Settings \ Application   Données \ assemblage \ dl3 \ KXPPAX6Y.ZCY \ A1MZ1499.1TR \ f0115d44 \ 91bb86eb_fe18c901

), mais lorsque j'arrive à la partie de mon code nécessitant cette DLL, elle ne la trouve pas.

Quelqu'un at-il une idée de ce que je dois faire différemment?

Était-ce utile?

La solution

Une fois que vous avez incorporé l'assembly tiers en tant que ressource, ajoutez du code pour vous abonner à AppDomain.AssemblyResolve de l'événement en cours au démarrage de l'application. Cet événement se déclenche chaque fois que le sous-système Fusion du CLR ne parvient pas à localiser un assembly en fonction de la vérification (stratégies) en vigueur. Dans le gestionnaire d'événements pour AppDomain.AssemblyResolve , chargez la ressource à l'aide de Assembly.GetManifestResourceStream et insérez son contenu sous forme de tableau d'octets dans l'élément Assembly.Load en surcharge. Voici comment une telle implémentation pourrait ressembler à C #:

AppDomain.CurrentDomain.AssemblyResolve += (sender, args) =>
{
    var resName = args.Name + ".dll";    
    var thisAssembly = Assembly.GetExecutingAssembly();    
    using (var input = thisAssembly.GetManifestResourceStream(resName))
    {
        return input != null 
             ? Assembly.Load(StreamToBytes(input))
             : null;
    }
};

StreamToBytes pourrait être défini comme:

static byte[] StreamToBytes(Stream input) 
{
    var capacity = input.CanSeek ? (int) input.Length : 0;
    using (var output = new MemoryStream(capacity))
    {
        int readLength;
        var buffer = new byte[4096];

        do
        {
            readLength = input.Read(buffer, 0, buffer.Length);
            output.Write(buffer, 0, readLength);
        }
        while (readLength != 0);

        return output.ToArray();
    }
}

Enfin, comme certains l'ont déjà mentionné, ILMerge peut être une autre option. à considérer, quoique un peu plus impliqué.

Autres conseils

En fin de compte, je l’ai fait presque exactement comme suggéré par raboof (et semblable à ce que dgvid a suggéré), à l’exception de quelques modifications mineures et de quelques omissions corrigées. J'ai choisi cette méthode car elle correspondait le mieux à ce que je cherchais et ne nécessitait pas l'utilisation d'un exécutable tiers, etc. Cela fonctionne très bien!

Voici à quoi ressemblait mon code:

EDIT: J'ai décidé de déplacer cette fonction vers un autre assemblage afin de pouvoir la réutiliser dans plusieurs fichiers (je passe juste dans Assembly.GetExecutingAssembly ()).

Il s’agit de la version mise à jour qui vous permet de transmettre l’assembly avec les DLL intégrées.

embeddedResourcePrefix est le chemin de chaîne de la ressource incorporée. Il s'agira généralement du nom de l'assembly suivi de toute structure de dossier contenant la ressource (par exemple, "MyComapny.MyProduct.MyAssembly.Resources" si la dll se trouve dans un dossier appelé. Ressources dans le projet). Il suppose également que la dll a une extension .dll.resource.

   public static void EnableDynamicLoadingForDlls(Assembly assemblyToLoadFrom, string embeddedResourcePrefix) {
        AppDomain.CurrentDomain.AssemblyResolve += (sender, args) => { // had to add =>
            try {
                string resName = embeddedResourcePrefix + "." + args.Name.Split(',')[0] + ".dll.resource";
                using (Stream input = assemblyToLoadFrom.GetManifestResourceStream(resName)) {
                    return input != null
                         ? Assembly.Load(StreamToBytes(input))
                         : null;
                }
            } catch (Exception ex) {
                _log.Error("Error dynamically loading dll: " + args.Name, ex);
                return null;
            }
        }; // Had to add colon
    }

    private static byte[] StreamToBytes(Stream input) {
        int capacity = input.CanSeek ? (int)input.Length : 0;
        using (MemoryStream output = new MemoryStream(capacity)) {
            int readLength;
            byte[] buffer = new byte[4096];

            do {
                readLength = input.Read(buffer, 0, buffer.Length); // had to change to buffer.Length
                output.Write(buffer, 0, readLength);
            }
            while (readLength != 0);

            return output.ToArray();
        }
    }

Il existe un outil appelé IlMerge qui peut accomplir cela: http://research.microsoft.com /~mbarnett/ILMerge.aspx

Vous pouvez ensuite créer un événement de construction similaire à celui-ci.

Définissez Path = "C: \ Program Files \ Microsoft \ ILMerge"

.

ilmerge /out:$(ProjectDir)\Deploy\LevelEditor.exe $ (rép_projet) \ bin \ version \ release.exe $ (rép_projet) \ bin \ version \ InteractLib.dll $ (rép_projet) \ bin \ version \ SpriteLib.dll $ (rép_projet) \ bin \ Release \ LevelLibrary.dll

J'ai réussi à faire ce que vous décrivez, mais comme la DLL tierce est également un assemblage .NET, je ne l'écris jamais sur le disque, je le charge simplement à partir de la mémoire.

Je récupère l'assemblage de ressources incorporé sous forme de tableau d'octets, comme suit:

        Assembly resAssembly = Assembly.LoadFile(assemblyPathName);

        byte[] assemblyData;
        using (Stream stream = resAssembly.GetManifestResourceStream(resourceName))
        {
            assemblyData = ReadBytesFromStream(stream);
            stream.Close();
        }

Ensuite, je charge les données avec Assembly.Load ().

Enfin, j'ajoute un gestionnaire à AppDomain.CurrentDomain.AssemblyResolve pour renvoyer mon assembly chargé lorsque le chargeur de types le recherche.

Voir Atelier .NET Fusion pour plus de détails.

Vous pouvez y parvenir remarquablement facilement avec Netz , un compresseur .net NET Executables & amp; Emballeur.

Au lieu d'écrire l'assembly sur le disque, vous pouvez essayer de faire Assembly.Load (byte [] rawAssembly) où vous créez rawAssembly à partir de la ressource incorporée.

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