É possível incorporar uma DLL pré-existente em um executável C # compilado (para que você tenha apenas um arquivo para distribuir)? Se for possível, como alguém faria isso?
Normalmente, sou legal em deixar as DLLs do lado de fora e fazer com que o programa de instalação lide com tudo, mas algumas pessoas no trabalho me perguntaram isso e eu sinceramente não sei.
Respostas:
Eu recomendo usar o Costura.Fody - de longe a melhor e mais fácil maneira de incorporar recursos em sua montagem. Está disponível como pacote NuGet.
Depois de adicioná-lo ao projeto, ele incorporará automaticamente todas as referências copiadas para o diretório de saída no seu assembly principal . Você pode limpar os arquivos incorporados adicionando um destino ao seu projeto:
Você também poderá especificar se deve incluir os pdb's, excluir determinados assemblies ou extrair os assemblies em tempo real. Tanto quanto sei, também são suportados conjuntos não gerenciados.
Atualizar
Atualmente, algumas pessoas estão tentando adicionar suporte ao DNX .
Atualização 2
Para a versão mais recente do Fody, você precisará do MSBuild 16 (portanto, Visual Studio 2019). O Fody versão 4.2.1 fará o MSBuild 15. (referência: Fody é suportado apenas no MSBuild 16 e acima. Versão atual: 15 )
fonte
Apenas clique 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.
Aqui está o meu post original: http://codeblog.larsholm.net/2011/06/embed-dlls-easily-in-a-net-assembly/
fonte
bytes
é nulo e, em caso afirmativo, retornar nulo lá. É possível que a dll não esteja nos recursos, afinal. Dois: Isso só funciona se a classe em si não tiver um "uso" para nada desse assembly. Para ferramentas de linha de comando, tive que mover meu código de programa real para um novo arquivo e criar um pequeno programa principal novo que apenas faça isso e depois chame o principal original na classe antiga..dll
nome contiver hífens (ietwenty-two.dll
), eles também serão substituídos por um sublinhado (ietwenty_two.dll
). Você pode alterar esta linha de código para isso:dllName = dllName.Replace(".", "_").Replace("-", "_");
Se eles são realmente assemblies gerenciados, você pode usar o ILMerge . Para DLLs nativas, você terá um pouco mais de trabalho a fazer.
Consulte também: Como uma DLL do Windows C ++ pode ser mesclada em um aplicativo C # exe?
fonte
C++
no link. O ILMerge também funciona com muita facilidade para o VB NET. Veja aqui https://github.com/dotnet/ILMerge . Obrigado @ Shog9Sim, é possível mesclar executáveis .NET com bibliotecas. Existem várias ferramentas disponíveis para realizar o trabalho:
Além disso, isso pode ser combinado com o Mono Linker , que remove o código não utilizado e, portanto, diminui o conjunto resultante.
Outra possibilidade é usar o .NETZ , que não apenas permite a compactação de um assembly, mas também pode empacotar as dlls diretamente no exe. A diferença para as soluções mencionadas acima é que o .NETZ não as mescla, elas permanecem montagens separadas, mas são empacotadas em um pacote.
fonte
O ILMerge pode combinar montagens em uma única montagem, desde que a montagem tenha apenas código gerenciado. Você pode usar o aplicativo de linha de comando ou adicionar referência ao exe e mesclar programaticamente. Para uma versão da GUI, existe o Eazfuscator e também o .Netz, ambos gratuitos. Os aplicativos pagos incluem BoxedApp e SmartAssembly .
Se você precisar mesclar assemblies com código não gerenciado, sugiro o SmartAssembly . Eu nunca tive soluços com o SmartAssembly, mas com todos os outros. Aqui, ele pode incorporar as dependências necessárias como recursos ao seu exe principal.
Você pode fazer tudo isso manualmente, sem precisar se preocupar se o assembly é gerenciado ou no modo misto, incorporando a dll aos seus recursos e depois confiando no Assembly do AppDomain
ResolveHandler
. Essa é uma solução única, adotando o pior caso, ou seja, montagens com código não gerenciado.A chave aqui é gravar os bytes em um arquivo e carregar a partir de sua localização. Para evitar problemas com galinhas e ovos, você deve garantir que declara o manipulador antes de acessar a montagem e que não acessa os membros da montagem (ou instancia algo que tenha que lidar com a montagem) dentro da peça de carregamento (resolução da montagem). Além disso, tome cuidado para garantir que
GetMyApplicationSpecificPath()
não haja nenhum diretório temporário, pois os arquivos temporários podem ser apagados por outros programas ou por você mesmo (não que sejam excluídos enquanto o programa estiver acessando a dll, mas pelo menos isso é um incômodo. localização). Observe também que você precisa escrever os bytes de cada vez, não é possível carregar a partir do local apenas porque a dll já reside lá.Para dlls gerenciadas, você não precisa escrever bytes, mas carregar diretamente do local da dll ou apenas ler os bytes e carregar o assembly da memória. Assim ou assim:
Se o conjunto é totalmente gerenciado, você pode ver esta ligação ou este a respeito de como carregar essas DLLs.
fonte
O trecho de Jeffrey Richter é muito bom. Em resumo, adicione as bibliotecas como recursos incorporados e adicione um retorno de chamada antes de qualquer outra coisa. Aqui está uma versão do código (encontrada nos comentários de sua página) que eu coloquei no início do método Main para um aplicativo de console (apenas verifique se todas as chamadas que usam a biblioteca estão em um método diferente do Main).
fonte
Para expandir no @ Bobby's asnwer acima. Você pode editar seu .csproj para usar o IL-Repack para empacotar automaticamente todos os arquivos em um único assembly quando criar.
Install-Package ILRepack.MSBuild.Task
Aqui está um exemplo simples que mescla ExampleAssemblyToMerge.dll à saída do projeto.
fonte
Você pode adicionar as DLLs como recursos incorporados e fazer com que seu programa descompacte-as no diretório do aplicativo na inicialização (após verificar se elas já existem).
Os arquivos de instalação são tão fáceis de criar, que não acho que valeria a pena.
EDIT: Essa técnica seria fácil com assemblies .NET. Com as DLLs que não são do .NET, seria muito mais trabalhoso (você teria que descobrir onde descompactar os arquivos, registrá-los e assim por diante).
fonte
Outro produto que pode lidar com isso com elegância é o SmartAssembly, no SmartAssembly.com . Esse produto, além de mesclar todas as dependências em uma única DLL, (opcionalmente) ofusca seu código, remove metadados extras para reduzir o tamanho do arquivo resultante e também pode otimizar a IL para aumentar o desempenho do tempo de execução.
Há também algum tipo de recurso de manipulação / relatório de exceção global que ele adiciona ao seu software (se desejado) que pode ser útil. Acredito que ele também tenha uma API de linha de comando para que você possa fazer parte do seu processo de compilação.
fonte
Nem a abordagem ILMerge nem Lars Holm Jensen manipulando o evento AssemblyResolve funcionarão para um host de plug-in. Digamos que o executável H carrega o conjunto P dinamicamente e o acessa via IP da interface definido em um conjunto separado. Para incorporar o IP no H, é necessário uma pequena modificação no código de Lars:
O truque para lidar com tentativas repetidas de resolver o mesmo assembly e retornar o existente em vez de criar uma nova instância.
EDIT: para que não estrague a serialização do .NET, retorne nulo para todos os assemblies não incorporados no seu, padronizando assim o comportamento padrão. Você pode obter uma lista dessas bibliotecas:
e retorne null se o assembly passado não pertencer
IncludedAssemblies
.fonte
O .NET Core 3.0 suporta nativamente a compilação em um único .exe
O recurso é ativado pelo uso da seguinte propriedade no seu arquivo de projeto (.csproj):
Isso é feito sem nenhuma ferramenta externa.
Veja minha resposta para esta pergunta para mais detalhes.
fonte
Pode parecer simplista, mas o WinRar oferece a opção de compactar vários arquivos em um executável de extração automática.
Possui muitas opções configuráveis: ícone final, extrair arquivos para o caminho especificado, arquivo para executar após a extração, logotipo / textos personalizados para o pop-up exibido durante a extração, nenhuma janela pop-up, texto do contrato de licença etc.
Pode ser útil em alguns casos .
fonte
Eu uso o compilador csc.exe chamado de um script .vbs.
No seu script xyz.cs, adicione as seguintes linhas após as diretivas (meu exemplo é para o Renci SSH):
As tags ref, res e ico serão selecionadas pelo script .vbs abaixo para formar o comando csc.
Em seguida, adicione o chamador do resolvedor de montagem no Principal:
... e adicione o resolvedor em algum lugar da classe:
Eu nomeio o script vbs para corresponder ao nome do arquivo .cs (por exemplo, ssh.vbs procura por ssh.cs); isso facilita muito a execução do script, mas se você não for um idiota como eu, um script genérico poderá capturar o arquivo .cs de destino em um arrastar e soltar:
fonte
É possível, mas não tão fácil, criar um assembly nativo / gerenciado híbrido em C #. Você estava usando C ++ em vez disso, seria muito mais fácil, pois o compilador Visual C ++ pode criar assemblies híbridos tão facilmente quanto qualquer outra coisa.
A menos que você tenha um requisito estrito para produzir uma montagem híbrida, eu concordo com o MusiGenesis que isso não vale a pena o trabalho de C #. Se você precisar fazer isso, talvez mude para C ++ / CLI.
fonte
Geralmente, você precisaria de algum tipo de ferramenta de pós-compilação para executar uma mesclagem de montagem como você está descrevendo. Existe uma ferramenta gratuita chamada Eazfuscator (eazfuscator.blogspot.com/), projetada para manipulação de bytecode que também lida com a fusão de montagem. Você pode adicionar isso a uma linha de comando pós-compilação com o Visual Studio para mesclar seus assemblies, mas sua milhagem variará devido a problemas que surgirão em qualquer cenário de fusão de assemblies que não seja equivalente.
Você também pode verificar se a compilação faz até que o NANT tenha a capacidade de mesclar assemblies após a compilação, mas eu não estou familiarizado o suficiente com o NANT para dizer se a funcionalidade está embutida ou não.
Há também muitos plugins do Visual Studio que executam a mesclagem de assemblies como parte da criação do aplicativo.
Como alternativa, se você não precisar fazer isso automaticamente, existem várias ferramentas, como o ILMerge, que mesclam os assemblies .net em um único arquivo.
O maior problema que tive com a mesclagem de assemblies é se eles usam espaços para nome semelhantes. Ou pior, faça referência a versões diferentes da mesma dll (meus problemas geralmente eram com os arquivos dll do NUnit).
fonte