Como uma dll do Windows C++ pode ser mesclada em um exe de aplicativo C#?

StackOverflow https://stackoverflow.com/questions/72264

  •  09-06-2019
  •  | 
  •  

Pergunta

Eu tenho um programa Windows C# que usa uma dll C++ para E/S de dados.Meu objetivo é implantar o aplicativo como um único EXE.

Quais são as etapas para criar esse executável?

Foi útil?

Solução

MOMAÇÃO ÚNICA DESPECIONAÇÃO DO Código Gerenciado e não gerenciado no domingo, 4 de fevereiro de 2007

Os desenvolvedores .NET adoram a implantação do XCOPY.E eles adoram componentes de montagem única.Pelo menos sempre me sinto meio desconfortável, se preciso usar algum componente e preciso lembrar de uma lista de arquivos para incluir também na montagem principal daquele componente.Então, quando recentemente tive que desenvolver um componente de código gerenciado e aumentá-lo com algum código não gerenciado de uma DLL C (obrigado a Marcus Heege por me ajudar com isso!), pensei em como tornar mais fácil a implantação das duas DLLs .Se fossem apenas dois assemblies, eu poderia ter usado o ILmerge para agrupá-los em apenas um arquivo.Mas isso não funciona para componentes de código misto com DLLs gerenciadas e não gerenciadas.

Então aqui está o que eu encontrei para uma solução:

Incluo todas as DLLs que desejo implantar no assembly principal do meu componente como recursos incorporados.Então configurei um construtor de classe para extrair essas DLLs como abaixo.A classe ctor é chamada apenas uma vez em cada AppDomain, então é uma sobrecarga insignificante, eu acho.

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

        ...

Neste exemplo incluí duas DLLs como recursos, uma sendo uma DLL de código não gerenciado e outra sendo uma DLL de código gerenciado (apenas para fins de demonstração), para mostrar como essa técnica funciona para ambos os tipos de código.

O código para extrair as DLLs em arquivos próprios é simples:

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

Trabalhar com um assembly de código gerenciado como esse é quase o mesmo de sempre.Você faz referência a ele (aqui:ManagedService.dll) no projeto principal do seu componente (aqui:MyLib), mas defina a propriedade Copy Local como false.Além disso, você vincula a montagem como um item existente e define a ação de construção como recurso incorporado.

Para o código não gerenciado (aqui:UnknownService.dll), basta vincular a DLL como um item existente e definir a ação de construção como recurso incorporado.Para acessar suas funções use o atributo DllImport normalmente, por exemplo.

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

É isso!Assim que você cria a primeira instância da classe com o ctor estático, as DLLs incorporadas são extraídas em seus próprios arquivos e estão prontas para uso como se você as tivesse implantado como arquivos separados.Contanto que você tenha permissões de gravação para o diretório de execução, isso funcionará bem para você.Pelo menos para código prototípico, acho que essa forma de implantação de assembly único é bastante conveniente.

Aproveitar!

link

Outras dicas

Tentar aplicativo em caixa;permite carregar todas as DLLs da memória.Além disso, parece que você pode até incorporar o tempo de execução .net.É bom criar aplicativos realmente independentes ...

Usar Fody.Costura pepita

  1. Abra sua solução -> Projeto -> Gerenciar pacotes Nuget
  2. Procurar Fody.Costura
  3. Compilar seu projeto.

É isso !

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

Você já experimentou o ILMerge? http://research.microsoft.com/~mbarnett/ILMerge.aspx

ILMerge é um utilitário que pode ser usado para mesclar vários assemblies .NET em um único assembly.Ele está disponível gratuitamente para uso na página Ferramentas e utilitários do Microsoft .NET Framework Developer Center.

Se você estiver construindo a DLL C++ com o /clr flag (todo ou parcialmente C++/CLI), então deve funcionar:

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

No entanto, não funcionará com uma DLL comum (nativa) do Windows.

Basta clicar com o botão direito do mouse no seu projeto no Visual Studio, escolha Propriedades do projeto -> Recursos -> Adicionar recurso -> Adicionar arquivo existente ... e inclua o código abaixo no seu app.xaml.cs ou 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);
}

Aqui está minha postagem original no blog:http://codeblog.larsholm.net/2011/06/embed-dlls-easily-in-a-net-assembly/

Instalar é uma solução.Para um aplicativo nativo do Windows, sugiro incorporar a DLL como um objeto de recurso binário e, em seguida, extraí-la em tempo de execução antes de precisar dela.

Montagem Inteligente pode fazer isso e muito mais.Se sua dll tiver código não gerenciado, ela não permitirá mesclar as dlls em um único assembly; em vez disso, poderá incorporar as dependências necessárias como recursos em seu exe principal.O outro lado, não é de graça.

Você pode fazer isso manualmente incorporando dll aos seus recursos e depois contando com o Assembly do AppDomain ResolveHandler.Quando se trata de dlls de modo misto, encontrei muitas das variantes e sabores de ResolveHandler abordagem para não funcionar para mim (todos os quais leem bytes dll na memória e leem a partir dele).Todos eles funcionaram para DLLs gerenciadas.Aqui está o que funcionou para mim:

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

A chave aqui é gravar os bytes em um arquivo e carregá-los de seu local.Para evitar o problema do ovo e da galinha, você deve garantir que declarou o manipulador antes de acessar a montagem e que não acessa os membros da montagem (ou instancia qualquer coisa que tenha que lidar com a montagem) dentro da peça de carregamento (resolução da montagem).Também tome cuidado para garantir GetMyApplicationSpecificPath() não é nenhum diretório temporário, pois os arquivos temporários podem ser tentados para serem apagados por outros programas ou por você mesmo (não que ele seja excluído enquanto o programa estiver acessando a dll, mas pelo menos é um incômodo.AppData é uma boa localização).Observe também que você tem que escrever os bytes toda vez, você não pode carregar do local apenas porque a dll já reside lá.

Se a montagem for totalmente não gerenciada, você poderá ver isto link ou esse sobre como carregar essas DLLs.

PostBuild de Xenocódigo pode empacotar gerenciados e não gerenciados em um único exe.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top