Einbetten von DLLs in eine kompilierte ausführbare Datei

618

Ist es möglich, eine bereits vorhandene DLL in eine kompilierte ausführbare C # -Datei einzubetten (sodass Sie nur eine Datei zum Verteilen haben)? Wenn es möglich ist, wie würde man das machen?

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

Merus
quelle
Ich würde empfehlen, dass Sie sich das Dienstprogramm .NETZ ansehen, das die Assembly auch mit einem Schema Ihrer Wahl komprimiert: http://madebits.com/netz/help.php#single
Nathan Baulch
2
Es ist möglich, aber Sie erhalten eine große ausführbare Datei (Base64 wird zum Codieren Ihrer DLL verwendet).
Paweł Dyda
Neben ILMerge empfehle ich ILMerge-Gui , wenn Sie sich nicht mit Befehlszeilenschaltern beschäftigen möchten . Es ist ein Open Source Projekt, wirklich gut!
Tyron
2
@ PawełDyda: Sie können binäre Rohdaten in ein PE-Bild einbetten (siehe RCDATA ). Keine Transformation erforderlich (oder empfohlen).
IInspectable

Antworten:

761

Ich empfehle dringend, Costura.Fody zu verwenden - bei weitem die beste und einfachste Möglichkeit, Ressourcen in Ihre Baugruppe einzubetten. Es ist als NuGet-Paket erhältlich.

Install-Package Costura.Fody

Nach dem Hinzufügen zum Projekt werden automatisch alle Referenzen, die in das Ausgabeverzeichnis kopiert wurden, in Ihr Hauptverzeichnis eingebettet Hauptbaugruppe.Möglicherweise möchten Sie die eingebetteten Dateien bereinigen, indem Sie Ihrem Projekt ein Ziel hinzufügen:

Install-CleanReferencesTarget

Sie können auch angeben, ob die PDFs eingeschlossen, bestimmte Assemblys ausgeschlossen oder die Assemblys im laufenden Betrieb extrahiert werden sollen. Soweit ich weiß, werden auch nicht verwaltete Assemblys unterstützt.

Aktualisieren

Derzeit versuchen einige Leute, Unterstützung für DNX hinzuzufügen .

Update 2

Für die neueste Fody-Version benötigen Sie MSBuild 16 (also Visual Studio 2019). Fody-Version 4.2.1 führt MSBuild 15 aus. (Referenz: Fody wird nur von MSBuild 16 und höher unterstützt. Aktuelle Version: 15 )

Matthias
quelle
79
Vielen Dank für diesen tollen Vorschlag. Installieren Sie das Paket und Sie sind fertig. Standardmäßig werden sogar Assemblys komprimiert.
Daniel
9
Ich hasse es, ein "Ich auch" zu sein, aber ich auch - das ersparte mir viel Kopfschmerzen! Vielen Dank für die Empfehlung! Dadurch konnte ich alles, was ich zum Umverteilen brauche, in eine einzige Exe packen und sie ist jetzt kleiner als die ursprüngliche Exe und die DLLs wurden kombiniert ... Ich benutze sie erst seit ein paar Tagen, daher kann ich nicht sagen, dass ich ' Ich habe es auf Herz und Nieren geprüft, aber wenn nichts Schlimmes auftaucht, kann ich sehen, dass dies ein reguläres Werkzeug in meiner Toolbox wird. Es funktioniert einfach!
Mattzell
19
Es ist cool. Es gibt jedoch einen Nachteil: Unter Windows generierte Assemblys sind nicht mehr binär kompatibel mit Mono Linux. Das heißt, Sie können die Assembly nicht direkt auf Linux Mono bereitstellen.
Tyler Long
7
Das ist schön! Wenn Sie vs2018 verwenden, vergessen Sie nicht, dass sich die Datei FodyWeavers.xml im Stammverzeichnis Ihres Projekts befindet.
Alan Deep
4
Als Ergänzung zum letzten Kommentar: Fügen Sie Ihrem Projekt die Datei FodyWeavers.xml mit folgendem Inhalt hinzu: <? Xml version = "1.0" encoding = "utf-8"?> <Weavers VerifyAssembly = "true"> <Costura /> </ Weavers>
HHenn
88

Klicken Sie einfach mit der rechten Maustaste auf Ihr Projekt in Visual Studio, wählen Sie Projekteigenschaften -> Ressourcen -> Ressource hinzufügen -> Vorhandene Datei hinzufügen ... und fügen Sie den folgenden Code in Ihre App.xaml.cs oder einen gleichwertigen Code ein.

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);
}

Hier ist mein ursprünglicher Blog-Beitrag: http://codeblog.larsholm.net/2011/06/embed-dlls-easily-in-a-net-assembly/

Lars Holm Jensen
quelle
6
Sie können dieses Verhalten sofort anwenden. Überprüfen Sie meine Antwort stackoverflow.com/a/20306095/568266
Matthias
4
Beachten Sie auch einen UNGLAUBLICH nützlichen Kommentar von AshRowe zu Ihrem Blog: Wenn Sie ein benutzerdefiniertes Thema installiert haben, wird versucht, die PresentationFramework.Theme-Assembly aufzulösen, die abstürzt und brennt! Gemäß dem Vorschlag von AshRowe können Sie einfach überprüfen, ob der dllName PresentationFramework wie folgt enthält: if (dllName.ToLower (). Contains ("Presentationframework")) return null;
YasharBahman
4
Zwei Kommentare dazu. Erstens: Sie sollten überprüfen, ob bytesnull ist, und wenn ja, dort null zurückgeben. Es ist doch möglich, dass die DLL nicht in den Ressourcen enthalten ist. Zweitens: Dies funktioniert nur, wenn diese Klasse selbst für nichts aus dieser Assembly eine "Verwendung" hat. Für Befehlszeilentools musste ich meinen eigentlichen Programmcode in eine neue Datei verschieben und ein kleines neues Hauptprogramm erstellen, das dies einfach tut und dann das ursprüngliche Hauptprogramm in der alten Klasse aufruft.
Nyerguds
2
Der Vorteil dieses Ansatzes besteht darin, dass keine externen Bibliotheken installiert werden müssen, um die gewünschte Funktionalität zu erreichen. Der Nachteil dieses Ansatzes ist, dass er nur nützlich ist, wenn es um verwaltete DLLs geht - Interop-DLLs (zumindest was meine Tests betrifft) lösen das AssemblyResolve-Ereignis nicht aus, und selbst wenn sie Assembly.Load (<Bytes eines Interops) ausgeführt haben .dll>) erzielt später nicht den gewünschten Effekt. stackoverflow.com/questions/13113131/… Nur mein 2c in dieser Angelegenheit
XDS
3
Nur für den Fall, dass jemand auf mein Problem stößt: Wenn der .dllName Bindestriche enthält (ztwenty-two.dll ), werden diese auch durch einen Unterstrich (dh twenty_two.dll) ersetzt. Sie können diese Codezeile folgendermaßen ändern:dllName = dllName.Replace(".", "_").Replace("-", "_");
Micah Vertal
87

Wenn es sich tatsächlich um verwaltete Assemblys handelt, können Sie ILMerge verwenden . Bei nativen DLLs müssen Sie etwas mehr arbeiten.

Siehe auch: Wie kann eine C ++ - Windows-DLL zu einer C # -Anwendungs-Exe zusammengeführt werden?

Shog9
quelle
Ich interessiere mich für die Zusammenführung von nativen DLLs. Gibt es Materialien?
Baiyan Huang
5
Siehe auch: stackoverflow.com/questions/108971/…
Milan Gardian
@BaiyanHuang siehe github.com/boxedapp/bxilmerge , die Idee ist, "ILMerge" für native DLLs zu erstellen.
Artem Razin
VB NET-Entwickler wie ich haben C++beim Link keine Angst davor. ILMerge funktioniert auch sehr einfach für VB NET. Siehe hier https://github.com/dotnet/ILMerge . Danke @ Shog9
Ivan Ferrer Villa
26

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

  • ILMerge ist ein Dienstprogramm, mit dem mehrere .NET-Assemblys zu einer einzigen Assembly zusammengeführt werden können.
  • Mono mkbundle packt eine Exe und alle Assemblys 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 besteht darin, dass .NETZ sie nicht zusammenführt, sondern separate Assemblys bleibt, sondern in einem Paket verpackt ist.

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

Bobby
quelle
NETZ scheint weg zu sein
Rbjz
Wow - ich dachte ich hätte es endlich gefunden, dann habe ich diesen Kommentar gelesen. Es scheint total weg zu sein. Gibt es Gabeln?
Mafii
Nun, es ist gerade zu GitHub gewechselt und nicht mehr auf der Website verlinkt ... also ist "total weg" eine Übertreibung. Höchstwahrscheinlich wird es nicht mehr unterstützt, aber es ist immer noch da. Ich habe den Link aktualisiert.
Bobby
20

ILMerge kann Assemblys zu einer einzigen Assembly kombinieren, sofern die Assembly nur Code verwaltet. Sie können die Befehlszeilen-App verwenden oder einen Verweis auf die Exe hinzufügen und programmgesteuert zusammenführen. Für eine GUI-Version gibt es Eazfuscator und auch .Netz, die beide kostenlos sind. Bezahlte Apps sind BoxedApp und SmartAssembly .

Wenn Sie Assemblys mit nicht verwaltetem Code zusammenführen müssen, würde ich SmartAssembly empfehlen . Ich hatte nie Probleme mit SmartAssembly, sondern mit allen anderen. Hier können die erforderlichen Abhängigkeiten als Ressourcen in Ihre Haupt-Exe eingebettet werden.

Sie können dies alles manuell tun, ohne sich Sorgen machen zu müssen, ob die Assembly verwaltet wird oder sich im gemischten Modus befindet, indem Sie die DLL in Ihre Ressourcen einbetten und sich dann auf die Assembly von AppDomain verlassen ResolveHandler. Dies ist eine One-Stop-Lösung, bei der der schlimmste Fall übernommen wird, dh Assemblys mit nicht verwaltetem Code.

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);
    };
}

Der Schlüssel hier ist, die Bytes in eine Datei zu schreiben und von ihrem Speicherort zu laden. Um Henne-Ei-Probleme zu vermeiden, müssen Sie sicherstellen, dass Sie den Handler deklarieren, bevor Sie auf die Baugruppe zugreifen, und dass Sie nicht auf die Baugruppenelemente zugreifen (oder alles instanziieren, was mit der Baugruppe zu tun hat). Stellen Sie außerdem sicher, dass GetMyApplicationSpecificPath()kein temporäres Verzeichnis vorhanden ist, da versucht werden könnte, temporäre Dateien von anderen Programmen oder von Ihnen selbst zu löschen (nicht, dass sie gelöscht werden, während Ihr Programm auf die DLL zugreift, aber zumindest ist dies ein Ärgernis. AppData ist gut Standort). Beachten Sie auch, dass Sie die Bytes jedes Mal schreiben müssen. Sie können nicht vom Speicherort laden, nur weil sich die DLL bereits dort befindet.

Für verwaltete DLLs müssen Sie keine Bytes schreiben, sondern direkt vom Speicherort der DLL laden oder einfach die Bytes lesen und die Assembly aus dem Speicher laden. So oder so:

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

    //or just

    return Assembly.LoadFrom(dllFullPath); //if location is known.

Wenn die Assembly vollständig unmanaged ist, können Sie diese sehen Link oder das , wie solche DLLs zu laden.

nawfal
quelle
Beachten Sie, dass die "Build-Aktion" der Ressource auf "Eingebettete Ressource" eingestellt sein muss.
Mavamaarten
@Mavamaarten Nicht unbedingt. Wenn es im Voraus zur Resources.resx des Projekts hinzugefügt wird, müssen Sie dies nicht tun.
Nyerguds
2
EAZfuscator ist jetzt kommerziell.
Telemat
16

Der Auszug von Jeffrey Richter ist sehr gut. Kurz gesagt, fügen Sie die Bibliotheken als eingebettete Ressourcen hinzu und fügen Sie vor allem anderen einen Rückruf hinzu. Hier ist eine Version des Codes (in den Kommentaren seiner Seite zu finden), den ich am Anfang der Main-Methode für eine Konsolen-App eingefügt habe (stellen Sie einfach sicher, dass alle Aufrufe, die die Bibliothek verwenden, eine andere Methode als Main haben).

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);
            }
        };
Steve
quelle
1
Hat es ein bisschen geändert, hat den Job gemacht, tnx Kumpel!
Sean Ed-Man
Das Projekt libz.codeplex.com verwendet diesen Prozess, führt jedoch auch einige andere Aufgaben aus, z. B. die Verwaltung des Ereignishandlers für Sie und einen speziellen Code, um " Managed Extensibility Framework-Kataloge " nicht zu beschädigen (was für sich genommen dieser Prozess stören würde)
Scott Chamberlain
Das ist großartig!! Danke @Steve
Ahmer Afzal
14

Um @ Bobbys Antwort oben zu erweitern. Sie können Ihre .csproj-Datei so bearbeiten, dass IL-Repack verwendet wird, um beim Erstellen automatisch alle Dateien in eine einzelne Assembly zu packen .

  1. Installieren Sie das Nuget ILRepack.MSBuild.Task-Paket mit Install-Package ILRepack.MSBuild.Task
  2. Bearbeiten Sie den AfterBuild-Abschnitt Ihrer .csproj

Hier ist ein einfaches Beispiel, das ExampleAssemblyToMerge.dll in Ihre Projektausgabe einfügt.

<!-- ILRepack -->
<Target Name="AfterBuild" Condition="'$(Configuration)' == 'Release'">

   <ItemGroup>
    <InputAssemblies Include="$(OutputPath)\$(AssemblyName).exe" />
    <InputAssemblies Include="$(OutputPath)\ExampleAssemblyToMerge.dll" />
   </ItemGroup>

   <ILRepack 
    Parallel="true"
    Internalize="true"
    InputAssemblies="@(InputAssemblies)"
    TargetKind="Exe"
    OutputFile="$(OutputPath)\$(AssemblyName).exe"
   />
</Target>
Josh
quelle
1
Die Syntax für IL-Repack wurde geändert. Überprüfen Sie die README.md auf dem verknüpften Github-Repo ( github.com/peters/ILRepack.MSBuild.Task ). Dieser Weg war der einzige, der für mich funktionierte, und ich konnte einen Platzhalter verwenden, um alle DLLs abzugleichen, die ich einschließen wollte.
Seabass77
8

Sie können die DLLs als eingebettete Ressourcen hinzufügen und sie dann beim Start von Ihrem Programm in das Anwendungsverzeichnis entpacken lassen (nachdem Sie überprüft haben, ob sie bereits vorhanden sind).

Setup-Dateien sind jedoch so einfach zu erstellen, dass ich nicht denke, dass sich dies lohnt.

BEARBEITEN: Diese Technik wäre mit .NET-Assemblys einfach. Mit Nicht-.NET-DLLs wäre es viel mehr Arbeit (Sie müssten herausfinden, wo Sie die Dateien entpacken und registrieren und so weiter).

MusiGenesis
quelle
Hier haben Sie einen großartigen Artikel, der erklärt, wie das geht: codeproject.com/Articles/528178/Load-DLL-From-Embedded-Resource
bläulich
8

Ein weiteres Produkt, das dies elegant handhaben kann, ist SmartAssembly bei SmartAssembly.com . Dieses Produkt verschmilzt nicht nur alle Abhängigkeiten zu einer einzigen DLL, sondern verschleiert (optional) Ihren Code, entfernt zusätzliche Metadaten, um die resultierende Dateigröße zu verringern, und kann die IL tatsächlich optimieren, um die Laufzeitleistung zu erhöhen.

Es gibt auch eine Art globale Ausnahmebehandlungs- / Berichtsfunktion, die Ihrer Software hinzugefügt wird (falls gewünscht), die nützlich sein könnte. Ich glaube, es hat auch eine Befehlszeilen-API, so dass Sie es Teil Ihres Build-Prozesses machen können.

Nathan
quelle
7

Weder der ILMerge-Ansatz noch Lars Holm Jensens Behandlung des AssemblyResolve-Ereignisses funktionieren für einen Plugin-Host. Angenommen, die ausführbare Datei H lädt die Assembly P dynamisch und greift über die in einer separaten Assembly definierte Schnittstellen- IP darauf zu . Um IP in H einzubetten , muss der Code von Lars ein wenig geändert werden:

Dictionary<string, Assembly> loaded = new Dictionary<string,Assembly>();
AppDomain.CurrentDomain.AssemblyResolve += (sender, args) =>
{   Assembly resAssembly;
    string dllName = args.Name.Contains(",") ? args.Name.Substring(0, args.Name.IndexOf(',')) : args.Name.Replace(".dll","");
    dllName = dllName.Replace(".", "_");
    if ( !loaded.ContainsKey( dllName ) )
    {   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);
        resAssembly = System.Reflection.Assembly.Load(bytes);
        loaded.Add(dllName, resAssembly);
    }
    else
    {   resAssembly = loaded[dllName];  }
    return resAssembly;
};  

Der Trick, um wiederholte Versuche zu verarbeiten, dieselbe Assembly aufzulösen und die vorhandene zurückzugeben, anstatt eine neue Instanz zu erstellen.

BEARBEITEN: Damit die Serialisierung von .NET nicht beeinträchtigt wird, stellen Sie sicher, dass für alle Assemblys, die nicht in Ihre Assemblys eingebettet sind, null zurückgegeben wird. Verwenden Sie dabei standardmäßig das Standardverhalten. Sie können eine Liste dieser Bibliotheken erhalten, indem Sie:

static HashSet<string> IncludedAssemblies = new HashSet<string>();
string[] resources = System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceNames();
for(int i = 0; i < resources.Length; i++)
{   IncludedAssemblies.Add(resources[i]);  }

und geben Sie einfach null zurück, wenn die übergebene Assembly nicht dazu gehört IncludedAssemblies.

Ant_222
quelle
Es tut uns leid, dass Sie es als Antwort und nicht als Kommentar veröffentlicht haben. Ich habe nicht das Recht, die Antworten anderer zu kommentieren.
Ant_222
5

.NET Core 3.0 unterstützt nativ das Kompilieren in eine einzelne EXE-Datei

Die Funktion wird durch die Verwendung der folgenden Eigenschaft in Ihrer Projektdatei (.csproj) aktiviert:

    <PropertyGroup>
        <PublishSingleFile>true</PublishSingleFile>
    </PropertyGroup>

Dies erfolgt ohne externes Werkzeug.

Siehe meine Antwort auf diese Frage für weitere Details.

Marcell Toth
quelle
3

Es mag simpel klingen, aber WinRar bietet die Möglichkeit, eine Reihe von Dateien in eine selbstextrahierende ausführbare Datei zu komprimieren.
Es gibt viele konfigurierbare Optionen: Endgültiges Symbol, Dateien in den angegebenen Pfad extrahieren, Datei, die nach dem Extrahieren ausgeführt werden soll, benutzerdefinierte Logos / Texte für Popups, die während des Extrahierens angezeigt werden, überhaupt kein Popup-Fenster, Lizenzvereinbarungstext usw.
Kann in einigen Fällen nützlich sein .

Ivan Ferrer Villa
quelle
Windows selbst hat ein ähnliches Tool namens iexpress. Hier ist ein Tutorial
Ivan Ferrer Villa
2

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

Fügen Sie in Ihrem Skript xyz.cs nach den Anweisungen die folgenden Zeilen ein (mein Beispiel ist für 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 Tags ref, res und ico werden vom folgenden .vbs-Skript abgerufen, um den Befehl csc zu bilden.

Fügen Sie dann den Assembly Resolver-Aufrufer im Main hinzu:

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:

    statische Assembly CurrentDomain_AssemblyResolve (Objektabsender, ResolveEventArgs-Argumente)
    {
        String resourceName = neuer AssemblyName (args.Name) .Name + ".dll";

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

    }}

Ich benenne das vbs-Skript so, dass es mit dem .cs-Dateinamen übereinstimmt (z. B. sucht ssh.vbs nach ssh.cs); Dies erleichtert das mehrfache Ausführen des Skripts erheblich. Wenn Sie jedoch kein Idiot wie ich sind, kann ein generisches Skript die CS-Zieldatei per Drag & Drop abrufen:

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

    'NEHMEN SIE DEN VBS-SCRIPT-NAMEN ALS ZIELDATEI-NAMEN
    '###################################################
    name_ = Split (wscript.ScriptName, ".") (0)

    'Holen Sie sich die externen DLLs und ICON-Namen aus der .CS-Datei
    '################################################### ######
    Const OPEN_FILE_FOR_READING = 1
    Setze objInputFile = fso.OpenTextFile (name_ & ".cs", 1)

    'LESEN SIE ALLES IN EINEN ARRAY
    '###############################
    inputData = Split (objInputFile.ReadAll, vbNewline)

    Für jede strData In inputData

        if left (strData, 7) = "// + ref>" dann 
            csc_references = csc_references & "/ reference:" & trim (replace (strData, "// + ref>", "")) & ""
        ende wenn

        if left (strData, 7) = "// + res>" dann 
            csc_resources = csc_resources & "/ resource:" & trim (replace (strData, "// + res>", "")) & ""
        ende wenn

        wenn left (strData, 7) = "// + ico>" dann 
            csc_icon = "/ win32icon:" & trim (replace (strData, "// + ico>", "")) & ""
        ende wenn
    Nächster

    objInputFile.Close


    'Kompilieren Sie die Datei
    '#################
    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)
Mark Llewellyn
quelle
0

Es ist möglich, aber nicht so einfach, eine hybride native / verwaltete Assembly in C # zu erstellen. Wenn Sie stattdessen C ++ verwenden, ist dies viel einfacher, da der Visual C ++ - Compiler Hybrid-Assemblys genauso einfach erstellen kann wie alles andere.

Wenn Sie nicht unbedingt eine Hybridbaugruppe herstellen müssen, stimme ich MusiGenesis zu, dass dies die Mühe mit C # nicht wirklich wert ist. Wenn Sie dies tun müssen, sollten Sie stattdessen auf C ++ / CLI umsteigen.

Chris Charabaruk
quelle
0

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

Sie können auch überprüfen, ob der Build die Fähigkeit hat, Assemblys nach dem Erstellen zusammenzuführen, aber ich bin mit NANT selbst nicht vertraut genug, um zu sagen, ob die Funktionalität integriert ist oder nicht.

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

Wenn dies nicht automatisch erfolgen muss, gibt es eine Reihe von Tools wie ILMerge, mit denen .net-Assemblys in einer einzigen Datei zusammengeführt werden.

Das größte Problem beim Zusammenführen von Assemblys ist, wenn sie ähnliche Namespaces verwenden. Oder schlimmer noch, verweisen Sie auf verschiedene Versionen derselben DLL (meine Probleme waren im Allgemeinen mit den NUnit-DLL-Dateien).

wllmsaccnt
quelle
1
Eazfuscator ruft einfach IlMerge, AFAIK an.
Bobby
+1 Bobby. Ich hätte mich daran erinnern sollen. Über alles, was Eazfucator für Sie tut, ist es, die tatsächlichen Aufrufe von ILMerge mit einer allgemeineren Konfigurationsdatei zu abstrahieren.
wllmsaccnt