Laden...

[erledigt] AssemblyResolve - einbinden dlls in die exe

Erstellt von Amosius vor 13 Jahren Letzter Beitrag vor 13 Jahren 5.237 Views
A
Amosius Themenstarter:in
31 Beiträge seit 2010
vor 13 Jahren
[erledigt] AssemblyResolve - einbinden dlls in die exe

Über den Artikel von Jeffrey Richter (hier der Artikel) bin ich auf die AssemblyResolve-Variante für meine Anliegen gestossen.
Habe die Historie des Forums und etliche Google Anfragen gestartet, leider ohne Erfolg. Vielleicht könnt ihr mir einen Rat geben:

Ich möchte gerne diverse Dlls von Drittanbietern in eine EXE einer WPF-Anwendung integrieren, analog dem oben genannten Artikel. Hierzu soll die DLL in die EXE eingebunden werden und durch das AssemblyResolve Event gefunden werden.

Meine Vorgehensweise:
Ich habe zusätzlich zum Verweis der DLL die Dll selbst zum Projekt hinzugefügt (hinzufügen -> vorhandenes Element) und den Build-Vorgang auf eingebettete Ressource umgestellt.

Folgenden Code habe ich verwendet:

using System;
using System.Reflection;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace Simple
{
    /// <summary>
    /// Interaktionslogik für MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {

            AppDomain.CurrentDomain.AssemblyResolve += (sender, args) =>
            {

                String resourceName = "AssemblyLoadingAndReflection." +

                   new AssemblyName(args.Name).Name + ".dll";

                using (var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName))
                {

                    Byte[] assemblyData = new Byte[stream.Length];

                    stream.Read(assemblyData, 0, assemblyData.Length);

                    return Assembly.Load(assemblyData);

                }

            };

            InitializeComponent();



            Test();

        }

        private void Test()
        {
            DLLClass Test = new DLLClass(); //hierzu ist die DLL notwendig
        }

    }
}

Ich bin mir nicht sicher ob die Position von AssemblyRessolve in dieser WPF-Anwendung die richtige ist. Zumindest wird diese ausgeführt, bevor
das Testobject initiiert wird.

Nun gehe ich in mein Debugverzeichnis und lösche die DLL, die das Programm ja benötigt. Die Anwendung kann ohne die DLL nicht ordnungsgemäß gestartet werden, obwohl ich an der Dateigröße der EXE sehe, dass die dll integriert sein muss.

Ich nehme an, dass ich das AssemblyResolve Event woanders hinterlegen muss?

Bin für Hinweise dankbar.

Amosius

2.187 Beiträge seit 2005
vor 13 Jahren

Hallo Amosius,

Dazu gibt es schon ein fertiges Programm, welches alles notwendige in deiner fertigen (normalen) Anwendung einbindet.
.Netz

Gruß
Juy Juka

A
Amosius Themenstarter:in
31 Beiträge seit 2010
vor 13 Jahren

Hallo JuyJuka,

vielen Dank, probiere ich aus.

Weiterhin würde ich gerne auch mal mein oberes Beispiel zum Laufen bringen.
Eine Idee woran das liegt?

Viele Grüße,
Amosius

D
201 Beiträge seit 2007
vor 13 Jahren

Ich nehme an, dass ich das AssemblyResolve Event woanders hinterlegen muss?
Amosius

Denke ich auch, denn im Artikel steht ja:

when your application initializes, register a callback method with the AppDomain’s ResolveAssembly event

Darum würde ich es mal so probieren (nicht im Window, sondern in der Application):


  /// <summary>
  /// Interaktionslogik für "App.xaml"
  /// </summary>
  public partial class App : Application
  {
    public App()
    {
      AppDomain.CurrentDomain.AssemblyResolve += (sender, args) =>
      {
        String resourceName = "AssemblyLoadingAndReflection." +
           new AssemblyName(args.Name).Name + ".dll";

        using (var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName))
        {
          Byte[] assemblyData = new Byte[stream.Length];
          stream.Read(assemblyData, 0, assemblyData.Length);
          return Assembly.Load(assemblyData);
        }
      };
    }
  }

Gruß

1.361 Beiträge seit 2007
vor 13 Jahren

Hi,

when your application initializes, register a callback method with the AppDomain’s ResolveAssembly event

Darum würde ich es mal so probieren (nicht im Window, sondern in der Application):

Ich würde es nicht im Konstruktor ("public App(){...}") definieren, sondern im Typinitialisierer ("static App(){...}").

beste Grüße
zommi

2.187 Beiträge seit 2005
vor 13 Jahren

Hallo,

Um sich am AssemblyResolve-Ereigniss anzumelden gibt es eigentlich nur eine gute stelle, wenn man die *.exe selber schreibt:
Die ersten 5 Zeilen in der Main-Methode.

Schreibt man nur eine Komponente die von anderen Geladen wird, dann muss man in jeder öffentlichen Klasse einen Typinitialisierer schreiben und dort eine Methode aufrufen, die das Anmelden übernimmt (und dafür sorgt, dass man sich nur einmal anmeldet).

Gruß
Juy Juka

A
Amosius Themenstarter:in
31 Beiträge seit 2010
vor 13 Jahren

Hallo,

vielen Dank für die Antworten.
Die Anwendung .Netz habe ich auf mein .NET Framework kompiliert. Leider war die Anwendung nach dem Zusammenfügen nicht mehr ganz die gleiche (Icons in der Anwendung waren verschwunden...).

ich habe aus Komfortgünden die folgende Funktion in die App.xaml.cs eingefügt,
die mir bei jedem kompilieren direkt eine fertige Executable erstellt:

        static App()
        {
            AppDomain.CurrentDomain.AssemblyResolve += (sender, args) =>
            {
                Console.WriteLine(new System.Reflection.AssemblyName(args.Name).Name);


                String resourceName = "MeinAnwendungsname." +

                    new System.Reflection.AssemblyName(args.Name).Name + ".dll";

                using (var stream = System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName))
                {

                    Byte[] assemblyData = new Byte[stream.Length];

                    stream.Read(assemblyData, 0, assemblyData.Length);

                    return System.Reflection.Assembly.Load(assemblyData);

                }

            };
        }       

Den Beitrag schliesse ich. Vielen Dank nochmals.