it-swarm.com.de

Wie kann eine C++ - Windows-DLL in eine C # -Anwendungs-EXE-Datei eingebunden werden?

Ich habe ein Windows C # -Programm, das eine C++ - DLL für Daten-E/A verwendet. Mein Ziel ist es, die Anwendung als einzelne EXE-Datei bereitzustellen.

Was sind die Schritte, um eine solche ausführbare Datei zu erstellen?

32
Noah

Bereitstellung von verwaltetem und nicht verwaltetem Code durch eine einzige Assembly Sonntag, 4. Februar 2007

.NET-Entwickler lieben die XCOPY-Bereitstellung. Und sie lieben einzelne Baugruppen. Zumindest fühle ich mich immer irgendwie unbehaglich, wenn ich eine Komponente verwenden muss und sich eine Liste der Dateien merken muss, die auch in der Hauptassembly dieser Komponente enthalten ist. Als ich vor kurzem eine verwaltete Code-Komponente entwickeln musste und sie mit etwas nicht verwaltetem Code aus einem C DLL erweitern musste (danke an Marcus Heege, dass er mir dabei geholfen hat!), Habe ich darüber nachgedacht, wie er erstellt wird einfacher, die beiden DLLs bereitzustellen. Wenn dies nur zwei Baugruppen wären, hätte ich ILmerge verwenden können, um sie in nur einer Datei zusammenzufassen. Dies funktioniert jedoch nicht für gemischte Code-Komponenten mit verwalteten und nicht verwalteten DLLs.

Ich habe also eine Lösung gefunden:

Ich füge alle DLLs ein, die ich mit der Hauptassembly meiner Komponente als eingebettete Ressourcen bereitstellen möchte. Dann habe ich einen Klassenkonstruktor eingerichtet, um diese DLLs wie unten beschrieben zu extrahieren. Die Klasse ctor wird in jeder AppDomain nur einmal aufgerufen, daher ist dies ein vernachlässigbarer Aufwand, denke ich.

namespace MyLib
{
    public class MyClass
    {
        static MyClass()
        {
            ResourceExtractor.ExtractResourceToFile("MyLib.ManagedService.dll", "managedservice.dll");
            ResourceExtractor.ExtractResourceToFile("MyLib.UnmanagedService.dll", "unmanagedservice.dll");
        }

        ...

In diesem Beispiel habe ich zwei DLLs als Ressourcen hinzugefügt, von denen eine eine nicht verwaltete Code-DLL und eine verwaltete Code DLL (nur zu Demonstrationszwecken) ist, um zu zeigen, wie diese Technik für beide Arten von Code funktioniert.

Der Code zum Extrahieren der DLLs in eigene Dateien ist einfach:

public static class ResourceExtractor
{
    public static void ExtractResourceToFile(string resourceName, string filename)
    {
        if (!System.IO.File.Exists(filename))
            using (System.IO.Stream s = System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName))
                using (System.IO.FileStream fs = new System.IO.FileStream(filename, System.IO.FileMode.Create))
                {
                    byte[] b = new byte[s.Length];
                    s.Read(b, 0, b.Length);
                    fs.Write(b, 0, b.Length);
                }
    }
}

Das Arbeiten mit einem verwalteten Code Assembly ist wie gewohnt - fast. Sie referenzieren es (hier: ManagedService.dll) im Hauptprojekt Ihrer Komponente (hier: MyLib), setzen jedoch die Copy Local-Eigenschaft auf false. Zusätzlich verknüpfen Sie in der Baugruppe als vorhandenes Element und setzen die Build-Aktion auf Embedded Resource.

Für den nicht verwalteten Code (hier: UnmanagedService.dll) verknüpfen Sie einfach in DLL als vorhandenes Element und setzen die Build-Aktion auf Embedded Resource. Um auf seine Funktionen zuzugreifen, verwenden Sie wie üblich das Attribut DllImport, z.

[DllImport("unmanagedservice.dll")] public extern static int Add(int a, int b);

Das ist es! Sobald Sie die erste Instanz der Klasse mit dem statischen Ctor erstellen, werden die eingebetteten DLLs in eigene Dateien extrahiert und können verwendet werden, als würden Sie sie als separate Dateien bereitstellen. Solange Sie Schreibberechtigungen für das Ausführungsverzeichnis haben, sollte dies für Sie funktionieren. Zumindest für prototypischen Code halte ich diese Art der Implementierung einer einzelnen Assembly für ziemlich bequem.

Genießen!

http://weblogs.asp.net/ralfw/archive/2007/02/04/single-Assembly-deployment-of-managed-and-unmanaged-code.aspx

16
Nick

Versuchen Sie boxedapp ; es erlaubt das Laden aller DLLs aus dem Speicher. Es scheint auch, dass Sie die .net-Laufzeitumgebung sogar einbetten können. Gut, um wirklich eigenständige Anwendungen zu erstellen ...

3
Art

Klicken Sie mit der rechten Maustaste in Visual Studio mit der rechten Maustaste auf Ihr Projekt, und wählen Sie Projekteigenschaften -> Ressourcen -> Ressource hinzufügen -> Vorhandene Datei hinzufügen… Aus. Fügen Sie den folgenden Code in App.xaml.cs oder einem entsprechenden 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 Blogbeitrag: http://codeblog.larsholm.net/2011/06/embed-dlls-easily-in-a-net-Assembly/

1

Verwenden Sie Fody.Costura nuget

  1. Öffnen Sie Ihre Lösung -> Projekt -> Nuget-Pakete verwalten
  2. Suche nach Fody.Costura
  3. Kompilieren Ihr Projekt

Das ist es !

Quelle: http://www.manuelmeyer.net/2016/01/net-power-tip-10-merging-assemblies/

1
automan

Haben Sie ILMerge ausprobiert? http://research.Microsoft.com/~mbarnett/ILMerge.aspx

ILMerge ist ein Dienstprogramm, mit dem mehrere .NET-Assemblys in einer einzigen Assembly zusammengeführt werden können. Sie steht auf der Tools & Utilities-Seite des Microsoft .NET Framework Developer Center kostenlos zur Verfügung. 

Wenn Sie C++ DLL mit dem Flag /clr (ganz oder teilweise C++/CLI) erstellen, sollte es funktionieren:

ilmerge /out:Composite.exe MyMainApp.exe Utility.dll

Es funktioniert jedoch nicht mit einem normalen (nativen) Windows DLL. 

1
Raithlin

Smart Assembly kann dies und mehr. Wenn Ihre DLL über nicht verwalteten Code verfügt, können Sie die DLLs nicht zu einer einzelnen Assembly zusammenführen. Stattdessen können Sie die erforderlichen Abhängigkeiten als Ressourcen in Ihr Hauptexe einbetten. Seine Kehrseite ist nicht frei.

Sie können dies manuell tun, indem Sie dll in Ihre Ressourcen einbetten und sich dabei auf die Assembly ResolveHandler von AppDomain verlassen. Wenn es um gemischte Dlls geht, habe ich festgestellt, dass viele der Varianten und Varianten von ResolveHandler nicht für mich funktionieren (alle, die DLL-Bytes in den Speicher lesen und daraus lesen). Sie alle arbeiteten für verwaltete DLLs. Folgendes hat für mich funktioniert:

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 Hühner- und Eierprobleme zu vermeiden, müssen Sie sicherstellen, dass Sie den Handler deklarieren, bevor Sie auf Assembly zugreifen, und dass Sie nicht auf die Assembly-Mitglieder zugreifen (oder alles instanziieren, was mit der Assembly zu tun hat), innerhalb des Ladeteils (Assembly lösen). Achten Sie auch darauf, dass GetMyApplicationSpecificPath() kein temporäres Verzeichnis 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 ein Ärgernis ist. AppData.) gute Lage). Beachten Sie auch, dass Sie die Bytes jedes Mal schreiben müssen, da Sie nicht von Ort laden können, da sich die DLL bereits dort befindet.

Wenn die Assembly vollständig nicht verwaltet wird, können Sie dieses link oder this sehen, wie solche DLLs geladen werden.

0
nawfal

Thinstall ist eine Lösung. Für eine native Windows-Anwendung würde ich vorschlagen, DLL als binäres Ressourcenobjekt einzubetten und dann zur Laufzeit zu extrahieren, bevor Sie es benötigen.

0
titanae