it-swarm-eu.dev

Come si può unire Windows C++ in un exe di un'applicazione C #?

Ho un programma Windows C # che usa una dll C++ per i/o i dati. Il mio obiettivo è distribuire l'applicazione come un singolo EXE.

Quali sono i passaggi per creare un simile eseguibile?

32
Noah

Implementazione di un singolo assieme di codice gestito e non gestito Domenica 4 febbraio 2007

Gli sviluppatori .NET adorano l'implementazione di XCOPY. E amano i singoli componenti dell'Assemblea. Almeno mi sento sempre a disagio, se devo usare qualche componente e ho bisogno di ricordare un elenco di file da includere anche con l'assembly principale di quel componente. Così quando di recente ho dovuto sviluppare un componente di codice gestito e ho dovuto aumentarlo con un codice non gestito da un C DLL (grazie a Marcus Heege per avermi aiutato con questo!), Ho pensato a come farlo più facile da distribuire le due DLL. Se si trattasse solo di due assembly, avrei potuto utilizzare ILmerge per comprimerli in un solo file. Ma questo non funziona per i componenti di codice misto con DLL gestite e non gestite.

Quindi ecco cosa mi è venuta in mente per una soluzione:

Includo tutte le DLL che voglio distribuire con l'assembly principale del mio componente come risorse incorporate. Quindi imposto un costruttore di classi per estrarre quelle DLL come di seguito. Il class ctor è chiamato solo una volta all'interno di ogni AppDomain, quindi è un overhead trascurabile, credo.

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

        ...

In questo esempio ho incluso due DLL come risorse, una essendo una DLL di codice non gestito e una essendo un codice gestito DLL (solo a scopo dimostrativo), per mostrare come questa tecnica funzioni per entrambi i tipi di codice.

Il codice per estrarre le DLL in file propri è semplice:

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

Lavorare con un codice gestito Assemblaggio come questo è lo stesso del solito - quasi. Si fa riferimento (qui: ManagedService.dll) nel progetto principale del componente (qui: MyLib), ma impostare la proprietà Copia locale su falso. Inoltre, si collega all'Assembly come elemento esistente e si imposta l'azione Build su Embedded Resource.

Per il codice non gestito (qui: UnmanagedService.dll) devi solo collegare il DLL come elemento esistente e impostare l'azione di compilazione su Risorsa incorporata. Per accedere alle sue funzioni usa l'attributo DllImport come al solito, ad es.

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

Questo è tutto! Non appena si crea la prima istanza della classe con il ctor statico, le DLL incorporate vengono estratte in file propri e pronte per essere utilizzate come se fossero state distribuite come file separati. Finché disponi di autorizzazioni di scrittura per la directory di esecuzione, questo dovrebbe funzionare correttamente. Almeno per codice prototipo, penso che questo modo di implementare un singolo Assembly sia abbastanza conveniente.

Godere!

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

16
Nick

Prova boxedapp ; consente di caricare tutte le DLL dalla memoria. Inoltre, sembra che tu possa persino incorporare .net runtime. Buono per creare applicazioni davvero standalone ...

3
Art

Basta fare clic con il pulsante destro del mouse sul progetto in Visual Studio, scegliere Proprietà progetto -> Risorse -> Aggiungi risorsa -> Aggiungi file esistente ... E includere il codice seguente in App.xaml.cs o equivalente.

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

Ecco il mio post sul blog originale: http://codeblog.larsholm.net/2011/06/embed-dlls-easily-in-a-net-Assembly/

1
Lars Holm Jensen

Usa Fody.Costura nuget

  1. Apri la tua soluzione -> Progetto -> Gestisci pacchetti Nuget
  2. Cerca Fody.Costura
  3. Compila your progetto

Questo è tutto !

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

1
automan

Hai provato ILMerge? http://research.Microsoft.com/~mbarnett/ILMerge.aspx

ILMerge è un'utilità che può essere utilizzata per unire più assembly .NET in un singolo assembly. È liberamente disponibile per l'utilizzo dalla pagina Strumenti e utilità del Centro per sviluppatori Microsoft .NET Framework. 

Se stai costruendo il _ _ DLLC++ con il flag /clr (tutto o parzialmente C++/CLI), allora dovrebbe funzionare:

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

Tuttavia, non funzionerà con un normale (nativo) Windows DLL. 

1
Raithlin

Smart Assembly può fare questo e altro. Se la tua DLL ha un codice non gestito, non ti permetterà di unire le DLL ad un singolo Assembly, invece di incorporare le dipendenze richieste come risorse per il tuo exe principale. Il suo rovescio, non è libero.

Puoi farlo manualmente inserendo dll nelle tue risorse e poi facendo affidamento su ResolveHandler di AppDomain. Quando si tratta di dll in modalità mista, ho trovato molte delle varianti e dei sapori dell'approccio ResolveHandler per non funzionare per me (tutto ciò che legge i byte dll in memoria e li legge). Hanno tutti lavorato per le DLL gestite. Ecco cosa ha funzionato per me:

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

La chiave qui è scrivere i byte in un file e caricare dalla sua posizione. Per evitare problemi con pollo e uova, devi assicurarti di dichiarare il gestore prima di accedere a Assembly e di non accedere ai membri dell'Assemblea (o creare un'istanza di tutto ciò che deve occuparsi dell'assembly) all'interno della parte di caricamento (risoluzione di assemblaggio). Assicurati inoltre che GetMyApplicationSpecificPath() non sia una directory temporanea in quanto i file temporanei potrebbero essere cancellati da altri programmi o da te (non che verranno cancellati mentre il tuo programma sta accedendo alla dll, ma almeno è una seccatura. buona posizione). Si noti inoltre che è necessario scrivere i byte ogni volta, non è possibile caricare dalla posizione semplicemente perché la dll risiede già lì.

Se l'Assembly è completamente non gestito, puoi vedere questo link o this su come caricare tali DLL.

0
nawfal

Thinstall è una soluzione. Per un'applicazione Windows nativa suggerirei di incorporare DLL come oggetto risorsa binaria, quindi estraendolo in runtime prima che sia necessario.

0
titanae