[C#] Einbetten von DLLs in eine kompilierte ausf├╝hrbare Datei


Answers

Wenn es sich tatsächlich um verwaltete Assemblys handelt, können Sie ILMerge . Für native DLLs müssen Sie etwas mehr Arbeit erledigen.

Siehe auch: Wie kann eine C ++ - Windows-DLL in eine C # -Anwendung exe eingebunden werden?

Question

Weißt du, ich habe nirgendwo eine gute Antwort dafür gefunden. Ist es möglich, eine bereits vorhandene DLL in eine kompilierte C # -Datei einzubetten (so dass Sie nur eine Datei verteilen müssen)? Wenn es möglich ist, wie würde man es tun?

Normalerweise bin ich cool, wenn ich die DLLs einfach draußen lasse und das Setup-Programm alles erledigt, aber es gab ein paar Leute bei der Arbeit, die mich das gefragt haben und ich weiß es ehrlich gesagt nicht.




Ich verwende den csc.exe-Compiler, der von einem .vbs-Skript aufgerufen wird.

Fügen Sie in Ihrem xyz.cs-Skript die folgenden Zeilen nach den Anweisungen hinzu (mein Beispiel ist für den Renci-SSH):

using System;
using Renci;//FOR THE SSH
using System.Net;//FOR THE ADDRESS TRANSLATION
using System.Reflection;//FOR THE Assembly

//+ref>"C:\Program Files (x86)\Microsoft\ILMerge\Renci.SshNet.dll"
//+res>"C:\Program Files (x86)\Microsoft\ILMerge\Renci.SshNet.dll"
//+ico>"C:\Program Files (x86)\Microsoft CAPICOM 2.1.0.2 SDK\Samples\c_sharp\xmldsig\resources\Traffic.ico"

Die ref-, res- und ico-Tags werden vom unten stehenden .vbs-Skript zur Bildung des csc-Befehls aufgenommen.

Fügen Sie dann den Aufruf des Assembly-Resolvers in den Hauptordner ein:

public static void Main(string[] args)
{
    AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
    .

... und fügen Sie den Resolver selbst irgendwo in der Klasse hinzu:

    static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
    {
        String resourceName = 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);
        }

    }

Ich benenne das vbs-Skript so, dass es dem .cs-Dateinamen entspricht (z. B. ssh.vbs sucht nach ssh.cs); Das macht das Ausführen des Skripts um ein Vielfaches einfacher, aber wenn Sie kein Idiot wie ich sind, könnte ein generisches Skript die CS-Zieldatei per Drag-and-Drop übernehmen:

    Dim name_,oShell,fso
    Set oShell = CreateObject("Shell.Application")
    Set fso = CreateObject("Scripting.fileSystemObject")

    'TAKE THE VBS SCRIPT NAME AS THE TARGET FILE NAME
    '################################################
    name_ = Split(wscript.ScriptName, ".")(0)

    'GET THE EXTERNAL DLL's AND ICON NAMES FROM THE .CS FILE
    '#######################################################
    Const OPEN_FILE_FOR_READING = 1
    Set objInputFile = fso.OpenTextFile(name_ & ".cs", 1)

    'READ EVERYTHING INTO AN ARRAY
    '#############################
    inputData = Split(objInputFile.ReadAll, vbNewline)

    For each strData In inputData

        if left(strData,7)="//+ref>" then 
            csc_references = csc_references & " /reference:" &         trim(replace(strData,"//+ref>","")) & " "
        end if

        if left(strData,7)="//+res>" then 
            csc_resources = csc_resources & " /resource:" & trim(replace(strData,"//+res>","")) & " "
        end if

        if left(strData,7)="//+ico>" then 
            csc_icon = " /win32icon:" & trim(replace(strData,"//+ico>","")) & " "
        end if
    Next

    objInputFile.Close


    'COMPILE THE FILE
    '################
    oShell.ShellExecute "c:\windows\microsoft.net\framework\v3.5\csc.exe", "/warn:1 /target:exe " & csc_references & csc_resources & csc_icon & " " & name_ & ".cs", "", "runas", 2


    WScript.Quit(0)



BoxedApp Sie die BoxedApp

Es kann eine DLL in jede App einbetten. Natürlich auch in C # geschrieben :)

Ich hoffe es hilft.







Wenn Sie ILMerge nicht mit Befehlszeilenschaltern belästigen wollen, empfehle ich ILMerge-Gui . Es ist ein Open-Source-Projekt, wirklich gut!




Ein weiteres Produkt, das elegant damit umgehen kann, ist SmartAssembly, auf SmartAssembly.com . Dieses Produkt wird nicht nur alle Abhängigkeiten in eine einzelne DLL zusammenführen, sondern (optional) Ihren Code verschleiern, zusätzliche Metadaten entfernen, um die resultierende Dateigröße zu reduzieren, und kann auch die IL optimieren, um die Laufzeitleistung zu erhöhen. Es gibt auch eine Art globales Ausnahmebehandlungs- / Berichtsmerkmal, das es Ihrer Software hinzufügt (falls gewünscht), das ich mir nicht die Zeit genommen habe, es zu verstehen, aber es könnte nützlich sein. Ich glaube, es hat auch eine Befehlszeilen-API, so dass Sie es Teil Ihres Build-Prozesses machen können.




Ja, es ist möglich, ausführbare .NET-Dateien mit Bibliotheken zusammenzuführen. Es stehen mehrere Tools zur Verfügung, um den Job zu erledigen:

  • ILMerge ist ein Dienstprogramm, mit dem mehrere .NET-Assemblies zu einer einzelnen Assembly zusammengeführt werden können.
  • Mono mkbundle , packt eine exe und alle Assemblies mit libmono in ein einziges Binärpaket.
  • IL-Repack ist eine FLOSS-Alternative zu ILMerge mit einigen zusätzlichen Funktionen.

Zusätzlich kann dies mit dem Mono-Linker kombiniert werden, der nicht verwendeten Code entfernt und dadurch die resultierende Baugruppe verkleinert.

Eine andere Möglichkeit ist die Verwendung von .NETZ , das nicht nur das Komprimieren einer Assembly ermöglicht, sondern auch die dlls direkt in die exe packen kann. Der Unterschied zu den oben genannten Lösungen ist, dass .NETZ sie nicht zusammenführt, sie bleiben separate Assemblies, sind aber in einem Paket verpackt.

.NETZ ist ein Open-Source-Tool, das die ausführbaren Dateien von Microsoft .NET Framework (EXE, DLL) komprimiert und komprimiert, um sie zu verkleinern.




Der Auszug von Jeffrey Richter ist sehr gut. Kurz gesagt, fügen Sie die Bibliothek als eingebettete Ressourcen hinzu und fügen Sie vor allem anderen einen Rückruf hinzu. Hier ist eine Version des Codes (in den Kommentaren auf seiner Seite gefunden), die ich am Anfang der Main-Methode für eine Konsole App (nur stellen Sie sicher, dass alle Aufrufe, die die Bibliothek verwenden, sind in einer anderen Methode zu Main).

AppDomain.CurrentDomain.AssemblyResolve += (sender, bargs) =>
        {
            String dllName = new AssemblyName(bargs.Name).Name + ".dll";
            var assem = Assembly.GetExecutingAssembly();
            String resourceName = assem.GetManifestResourceNames().FirstOrDefault(rn => rn.EndsWith(dllName));
            if (resourceName == null) return null; // Not found, maybe another handler will find it
            using (var stream = assem.GetManifestResourceStream(resourceName))
            {
                Byte[] assemblyData = new Byte[stream.Length];
                stream.Read(assemblyData, 0, assemblyData.Length);
                return Assembly.Load(assemblyData);
            }
        };



Im Allgemeinen benötigen Sie eine Art Post-Build-Tool, um eine Assembly Merge durchzuführen, wie Sie es beschreiben. Es gibt ein kostenloses Tool namens Eazfuscator (eazfuscator.blogspot.com/), das für das Bytecode Mangling entwickelt wurde und auch das Zusammenfügen von Assemblys übernimmt. Sie können dies in einer Post-Build-Befehlszeile mit Visual Studio hinzufügen, um Ihre Assemblys zusammenzuführen, aber Ihre Laufleistung variiert aufgrund von Problemen, die bei nicht zusammengesetzten Zusammenführungsszenarien auftreten.

Sie könnten auch überprüfen, ob der Build die Möglichkeit bietet, NANT nach dem Erstellen Assemblys zusammenzufügen, aber ich bin nicht genug vertraut mit NANT, um zu sagen, ob die Funktionalität eingebaut ist oder nicht.

Es gibt auch viele Visual Studio-Plugins, die das Zusammenführen von Assemblys als Teil des Erstellens der Anwendung durchführen.

Alternativ, wenn Sie dies nicht automatisch durchführen müssen, gibt es eine Reihe von Tools wie ILMerge, die .net-Assemblies in eine einzige Datei zusammenführen.

Das größte Problem, das ich beim Zusammenführen von Assemblys hatte, ist, wenn sie ähnliche Namespaces verwenden. Oder schlimmer, verweisen Sie auf verschiedene Versionen der gleichen DLL (meine Probleme waren in der Regel mit den NUnit DLL-Dateien).