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.
Antworten:
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.
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:
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 )
quelle
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.
Hier ist mein ursprünglicher Blog-Beitrag: http://codeblog.larsholm.net/2011/06/embed-dlls-easily-in-a-net-assembly/
quelle
bytes
null 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..dll
Name Bindestriche enthält (ztwenty-two.dll
), werden diese auch durch einen Unterstrich (dhtwenty_two.dll
) ersetzt. Sie können diese Codezeile folgendermaßen ändern:dllName = dllName.Replace(".", "_").Replace("-", "_");
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?
quelle
C++
beim Link keine Angst davor. ILMerge funktioniert auch sehr einfach für VB NET. Siehe hier https://github.com/dotnet/ILMerge . Danke @ Shog9Ja, es ist möglich, ausführbare .NET-Dateien mit Bibliotheken zusammenzuführen. Es stehen mehrere Tools zur Verfügung, um die Aufgabe zu erledigen:
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.
quelle
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.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:
Wenn die Assembly vollständig unmanaged ist, können Sie diese sehen Link oder das , wie solche DLLs zu laden.
quelle
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).
quelle
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 .
Install-Package ILRepack.MSBuild.Task
Hier ist ein einfaches Beispiel, das ExampleAssemblyToMerge.dll in Ihre Projektausgabe einfügt.
quelle
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).
quelle
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.
quelle
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:
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:
und geben Sie einfach null zurück, wenn die übergebene Assembly nicht dazu gehört
IncludedAssemblies
.quelle
.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:
Dies erfolgt ohne externes Werkzeug.
Siehe meine Antwort auf diese Frage für weitere Details.
quelle
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 .
quelle
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):
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:
... und fügen Sie den Resolver selbst irgendwo in der Klasse hinzu:
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:
quelle
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.
quelle
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).
quelle