Įterpti DLL į sukurtą vykdomąjį failą

Žinote, aš niekada nemačiau gero atsakymo. Ar galima įdėti esamą DLL į sukompiliuotą C # vykdomąjį failą (kad galėtumėte platinti tik vieną failą)? Jei tai įmanoma, kaip tai padaryti?

Paprastai norėčiau palikti biblioteką išorėje ir turėti montuotoją, apdoroti viską, bet darbe buvo keletas žmonių, kurie manęs paklausė, ir aš sąžiningai nežinau.

522
10 окт. nustatė Merus spalio 10 d. 2008-10-10 02:11 '08, 02:11, 2008-10-10 02:11
@ 19 atsakymų

Aš labai rekomenduoju naudoti Costura.Fody - tai geriausias ir paprasčiausias būdas įtvirtinti išteklius į savo kūrinį . Jis yra „NuGet“ paketas.

 Install-Package Costura.Fody 

Įtraukus jį į projektą, jis automatiškai įterpia visas nuorodas, nukopijuotas į pagrindinio surinkimo katalogą. Galbūt norėsite išvalyti įterptus failus pridėdami tikslą į savo projektą:

 Install-CleanReferencesTarget 

Taip pat galite nurodyti, ar įtraukti pdb, išskirti tam tikras sąrankas, ar ištraukti rinkinius. Kiek aš žinau, taip pat remiamos nevaldomos asamblėjos.

Atnaujinti

Šiuo metu kai kurie žmonės bando pridėti DNX palaikymą .

656
01 дек. Atsakymą pateikė Matthias. 2013-12-01 00:53 '13 - 0:53 2013-12-01 00:53

Jei jie tikrai skatina statinius , galite naudoti „ ILMerge“ . Vietiniams DLL failams reikia šiek tiek daugiau darbo.

border=0

Taip pat žiūrėkite: Kaip sujungti C ++ DLL į EXE C # programą?

77
10 окт. atsakymas, kurį pateikė Shog9 Oct 10. 2008-10-10 02:17 '08, 2:17, 2008-10-10 02:17

Tiesiog spustelėkite savo projektą „Visual Studio“, pasirinkite „Projekto ypatybės“ → „Ištekliai“ → „Pridėti šaltinį“ → „Pridėti esamą failą“). Ir įtraukite žemiau esantį kodą savo „App.xaml.cs“ arba jo atitikmenyje.

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

Čia yra mano originalus dienoraščio įrašas: http://codeblog.larsholm.net/2011/06/embed-dlls-easily-in-a-net-assembly/

76
15 июня '11 в 21:20 2011-06-15 21:20 atsakymą pateikė Lars Holm Jensen birželio 15 d., 11:20 2011-06-15 21:20

Taip, galima sujungti .NET vykdomuosius failus su bibliotekomis. Šiai užduočiai yra keletas įrankių:

  • ILMerge yra įrankis, kuriuo galima sujungti kelis .NET rinkinius į vieną surinkimą.
  • „Mono mkbundle“ , „exe“ paketai ir visi elementai su „libmono“ vienu binariniu paketu.
  • IL-Repack yra FLOSS, alternatyva ILMerge, su kai kuriomis papildomomis funkcijomis.

Be to, jis gali būti derinamas su „ Mono Linker“ , kuris pašalina nepanaudotą kodą ir todėl sumažina gautą surinkimą.

Kita galimybė - naudoti . NETZ , kuri ne tik leidžia suspausti surinkimą, bet ir gali tiesiogiai paketuoti DLL į Exe. Skirtumas nuo pirmiau pateiktų sprendimų yra tas, kad .NETZ jų nesujungia, jie išlieka atskiri mazgai, bet yra supakuoti į vieną paketą.

.NETZ yra atviro kodo įrankis, kuris suspausto ir paketuoja Microsoft .NET Framework vykdomuosius failus (EXE, DLL), kad jie būtų mažesni.

24
28 окт. Bobby paskelbtas spalio 28 d. 2010-10-28 17:06 '10, 17:06, 2010-10-28 17:06

ILMerge gali sujungti agregatus su vienu surinkimu, jei surinkimas yra tik valdomas kodas. Galite naudoti komandinės eilutės programą arba pridėti nuorodą į exe ir programiškai sujungti. GUI versijai taip pat yra Eazfuscator . Netz , kurie abu yra nemokami. Mokamos programos apima „ BoxedApp“ ir „ SmartAssembly“ ,

Jei jums reikia sujungti nereguliuojamų kodų rinkinius, siūlau SmartAssembly . Aš niekada nesijaudinau su „ SmartAssembly“ , bet su visais kitais. Čia jis gali įterpti būtinas priklausomybes kaip išteklius į jūsų pagrindinį.

Jūs tai negalite nerimauti rankiniu būdu, jei surinkimas yra kontroliuojamas arba mišrus režimas, įdėję DLL į savo išteklius, o tada pasikliaudami „AppDomain“ ResolveHandler . Tai „vieno >

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

Svarbiausias dalykas yra įrašyti bytes į failą ir atsisiųsti iš jo vietos. Kad išvengtumėte problemų su vištiena ir kiaušiniu, turite įsitikinti, kad prieš patekdami į surinkimo įrenginį, skelbiate, kad jūs neturite prieigos prie surinkimo narių (arba sukurkite visko, susijusio su surinkimu), apkrovos (surinkimo) dalyje. Taip pat būkite atsargūs, kad „ GetMyApplicationSpecificPath() nebūtų laikinasis katalogas, nes laikini failai gali būti ištrinti kitomis programomis arba patys (ir ne tai, kad jie bus ištrinti, kol programa neprisijungs prie DLL, bet bent jau jos „AppData“ yra gera vieta). Taip pat atkreipkite dėmesį, kad kiekvieną kartą turite rašyti baitus, jūs negalite įkelti tik iš vietos ", nes dll jau yra".

Valdomiems DLL failams nereikia rašyti baitų, bet įkelti tiesiogiai iš dll vietos arba tiesiog skaityti baitus ir įkelti surinkimą iš atminties. Kažkas panašaus:

  using (Stream s = Assembly.GetEntryAssembly().GetManifestResourceStream(typeof(Program).Namespace + ".Resources." + dllName)) { byte[] data = new byte[stream.Length]; s.Read(data, 0, data.Length); return Assembly.Load(data); } //or just return Assembly.LoadFrom(dllFullPath); //if location is known. 

Jei kūrimas yra visiškai nevaldomas, galite pamatyti šią nuorodą arba tai, kaip įkelti tokius DLL.

16
15 мая '12 в 14:46 2012-05-15 14:46 atsakymas pateikiamas nawfal 15 d., 12 val. 14:46 2012-05-15 14:46

Jei norite pereiti prie „ @Bobby asnwer“ aukščiau. Jūs galite redaguoti savo .csproj, kad naudodami IL-Repack automatiškai pakuotumėte visus failus į vieną rinkinį.

  • Įdiekite „nuget ILRepack.MSBuild.Task“ paketą naudodami „ Install-Package ILRepack.MSBuild.Task
  • Redaguokite savo .csproj skyrių AfterBuild

Štai paprastas pavyzdys, kuris integruoja exampleAssemblyToMerge.dll į jūsų projektą.

 <!-- ILRepack --> <Target Name="AfterBuild" Condition="'$(Configuration)' == 'Release'"> <ItemGroup> <InputAssemblies Include="$(OutputPath)\$(AssemblyName).exe" /> <InputAssemblies Include="$(OutputPath)\ExampleAssemblyToMerge.dll" /> </ItemGroup> <ILRepack Parallel="true" Internalize="true" InputAssemblies="@(InputAssemblies)" TargetKind="Exe" OutputFile="$(OutputPath)\$(AssemblyName).exe" /> </Target> 
11
07 марта '15 в 23:40 2015-03-07 23:40 Atsakymą davė Josh kovo 7 d. 15 val. 11:40 2015-03-07 23:40

Jeffrey Richter ištrauka yra labai gera. Trumpai tariant, pridėkite biblioteką kaip integruotus išteklius ir pridėkite atgalinį ryšį prieš ką nors kitą. Čia yra kodo versija (pateikta jo puslapio komentaruose), kurią aš įdėjau į pagrindinio metodo pradžią konsolės programai (tik įsitikinkite, kad bet kokie skambučiai, kuriuose naudojama biblioteka, turi skirtingą pagrindinio metodą).

 AppDomain.CurrentDomain.AssemblyResolve += (sender, bargs) => { String dllName = new AssemblyName(bargs.Name).Name + ".dll"; var assem = Assembly.GetExecutingAssembly(); String resourceName = assem.GetManifestResourceNames().FirstOrDefault(rn => rn.EndsWith(dllName)); if (resourceName == null) return null; // Not found, maybe another handler will find it using (var stream = assem.GetManifestResourceStream(resourceName)) { Byte[] assemblyData = new Byte[stream.Length]; stream.Read(assemblyData, 0, assemblyData.Length); return Assembly.Load(assemblyData); } }; 
11
06 нояб. Atsakymą Steve pateikė lapkričio 6 d. 2013-11-06 10:04 '13, 10:04, 2013-11-06 10:04

Rekomenduojame patikrinti „.NETZ“ įrankį, kuris taip pat suspausto surinkimą pagal pasirinktą schemą:

http://madebits.com/netz/help.php#single

7
10 окт. Atsakymą pateikė Nathan Baulch spalio 10 d. 2008-10-10 02:28 '08 at 2:28 2008-10-10 02:28

Nei „ILMerge“, nei „Lars Holm Jensen“, kurie tvarko „AssemblyResolve“ renginį, veiks „plugin“ priegloboje. Pasakykite, kad vykdomasis H dinamiškai įkelia rinkinį P ir pasiekia jį per IP sąsają, apibrėžtą atskirame rinkinyje. Norėdami įdėti IP į H, reikia šiek tiek pakeisti „Lars“ kodą:

 Dictionary<string, Assembly> loaded = new Dictionary<string,Assembly>(); AppDomain.CurrentDomain.AssemblyResolve += (sender, args) => { Assembly resAssembly; string dllName = args.Name.Contains(",") ? args.Name.Substring(0, args.Name.IndexOf(',')) : args.Name.Replace(".dll",""); dllName = dllName.Replace(".", "_"); if ( !loaded.ContainsKey( dllName ) ) { 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); resAssembly = System.Reflection.Assembly.Load(bytes); loaded.Add(dllName, resAssembly); } else { resAssembly = loaded[dllName]; } return resAssembly; }; 

Trikis, skirtas pakartotiniams bandymams išspręsti tą pačią sąranką ir grąžinti esamą, o ne sukurti naują instanciją.

EDIT: taip, kad ji nepažeistų .NET serializacijos, būtinai grąžinkite null visiems asamblėjoms, kurios nėra įmontuotos į jūsų sistemą, taip nesilaikydami standartinio elgesio. Šių bibliotekų sąrašą galite gauti:

 static HashSet<string> IncludedAssemblies = new HashSet<string>(); string[] resources = System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceNames(); for(int i = 0; i < resources.Length; i++) { IncludedAssemblies.Add(resources[i]); } 

ir tiesiog grąžinkite nulį, jei perduotas kūrinys nepriklauso „ IncludedAssemblies .

6
09 окт. atsakymas pateikiamas Ant_222 09 okt. 2013-10-09 13:55 '13, 13:55, 2013-10-09 13:55

Pažymėkite boxedapp

Jis gali įdėti dll į bet kurią programą. Jis taip pat parašytas C #, žinoma :)

Tikiuosi, kad tai padės.

6
14 июля '09 в 11:42 2009-07-14 11:42 Atsakymas duotas Art. Liepos 14 d., 09:42, 2009-07-14 11:42

Galite įterpti DLL kaip integruotus išteklius ir paleisti juos į programos katalogą paleisties metu (patikrinę, ar jie yra).

Konfigūracijos failai yra tokie paprasti, kad nemanau, kad tai buvo verta.

EDIT: Šis metodas bus lengvas .NET rinkiniais. Tai būtų daug daugiau dirbti su ne NET DLL failus (jums reikės išsiaiškinti, kur išpakuoti failus ir juos užregistruoti ir tt).

6
10 окт. Atsakymas pateikiamas MusiGenesis 10 okt. 2008-10-10 02:14 '08 at 2:14 2008-10-10 02:14

Kitas produktas, kuris gali tai apdoroti, yra SmartAssembly, SmartAssembly.com . Šis produktas, be visų priklausomybių sujungimo į vieną DLL (neprivaloma), užblokuoja jūsų kodą, pašalina papildomus metaduomenis, kad sumažintų gautą failo dydį, ir iš tikrųjų gali optimizuoti IL, kad būtų galima geriau veikti vykdymo metu. Taip pat yra tam tikra pasaulinė išimčių tvarkymo / tvarkymo funkcija, kuri pridedama prie jūsų programinės įrangos (jei reikia), kurią neradau laiko suprasti, bet gali būti naudinga. Manau, kad jis taip pat turi komandų eilutės API, kad galėtumėte ją įtraukti į savo kūrimo procesą.

5
10 окт. Atsakyti Nathan 10 oct. 2008-10-10 02:40 '08 at 2:40 2008-10-10 02:40

ILMerge daro būtent tai, ko norite.

4
28 окт. atsakymas, pateiktas c . 2010-10-28 17:04 '10, 17:04, 2010-10-28 17:04

Be ILMerge , jei nenorite nerimauti dėl komandinės eilutės perjungimo, tikrai rekomenduoju ILMerge-Gui . Tai atviro kodo projektas, labai geras!

3
19 дек. Tirono atsakymas 19 d. 2012-12-19 15:45 '12 15:45 2012-12-19 15:45

Tai gali atrodyti paprasta, bet „WinRar“ suteikia galimybę suspausti failų krūvą į savarankiškai ištraukiamą vykdomąjį failą.
Jis turi daug pritaikomų parametrų: galutinę piktogramą, failų išgavimą tam tikrame kelyje, failą, skirtą atlikti po ištraukimo, pasirinktinį logotipą / tekstus iškylančiajam > Gali būti naudinga kai kuriais atvejais.

2
20 янв. Atsakymą pateikė Ivan Ferrer Villa sausio 20 2015-01-20 12:03 '15, 12:03 2015-01-20 12:03

Naudoju csc.exe kompiliatorių, vadinamą .vbs scenariju.

„Xyz.cs“ scenarijuje po direktyvų pridėkite šias eilutes (mano SSH Renci pavyzdys):

 using System; using Renci;//FOR THE SSH using System.Net;//FOR THE ADDRESS TRANSLATION using System.Reflection;//FOR THE Assembly //+ref>"C:\Program Files (x86)\Microsoft\ILMerge\Renci.SshNet.dll" //+res>"C:\Program Files (x86)\Microsoft\ILMerge\Renci.SshNet.dll" //+ico>"C:\Program Files (x86)\Microsoft CAPICOM 2.1.0.2 SDK\Samples\c_sharp\xmldsig\resources\Traffic.ico" 

Ref, res ir ico žymės bus sukompiliuotos po .vbs scenarijaus, kad sudarytumėte csc komandą.

Tada pridėkite skambinančiojo surinkimo mazgo į Main:

 public static void Main(string[] args) { AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve); . 

... ir pridėkite pačią rezoliuciją kur nors klasėje:

 statinis surinkimo srovėsDomain_AssemblyResolve (objekto siuntėjas, ResolveEventArgs args) { String resourceName = naujas AssemblyName (args.Name) .Name + ".dll"; naudojant (var stream = Assembly.GetExecutingAssembly (). GetManifestResourceStream (resourceName)) { Baitas [] assemblyData = naujas baitas [srautas. Ilgis]; stream.Read (assemblyData, 0, assemblyData.Length); grįžti asamblėja. } }

Skambinu vbs scenarijumi, kad atitiktų .cs failo pavadinimą (pvz., Ssh.vbs ieško ssh.cs); tai palengvina scenarijaus paleidimą, tačiau jei nesate idiotas, kaip man, tada bendrinamasis scenarijus gali nukreipti .cs failą iš vilkimo ir nuleidimo:

 Dim name_, oShell, fso Nustatyti oShell = CreateObject („Shell.Application“) Nustatyti fso = CreateObject („Scripting.fileSystemObject“) „PIRKITE VBS SCRIPT NAME kaip tikslinės failo pavadinimą '############################################################## name_ = Split (wscript.ScriptName, ".") (0) „GAUTI IŠORĖS DLL IR ICONO PAVADINIMUS IŠ '############################################################### ###### Const OPEN_FILE_FOR_READING = 1 Nustatyti objInputFile = fso.OpenTextFile (vardas_ ir „.cs“, 1) „SKAITYKITE VISI ARRAYJE „############################# inputData = Split (objInputFile.ReadAll, vbNewline) Kiekvienam strData In inputData jei kairėje (strData, 7) = "// + ref>", tada  csc_references = csc_references  "/ nuoroda:" ir apdaila (pakeiskite (strData, "// + ref>", ""))  "" pabaigos, jei jei kairėje (strData, 7) = "// + res>", tada  csc_resources = csc_resources  "/ resource:"  apdaila (pakeiskite (strData, "// + res>", ""))  "" pabaigos, jei jei kairėje (strData, 7) = "// + ico>"  csc_icon = "/ win32icon:" ir apdaila (pakeiskite (strData, "// + ico>", ""))  "" pabaigos, jei Toliau objInputFile.Close „KOMPLEKTUOTI FILE „################ oShell.ShellExecute "c: >
1
28 апр. Mark Llewellyn atsakymas balandžio 28 d 2016-04-28 16:58 '16 at 16:58 pm 2016-04-28 16:58

Galima, bet ne taip paprasta, sukurti hibridinį surinkimo / tvarkymo rinkinį C #. Jei naudojote „C ++“, tai būtų daug lengviau, nes „Visual C ++“ kompiliatorius gali sukurti hibridinius mazgus taip pat lengvai, kaip ir visa kita.

Jei neturite griežto reikalavimo sukurti hibridinę asamblę, sutinku su MusiGenesis, kad tai nėra verta daryti su C #. Jei norite tai padaryti, galbūt peržiūrėkite perėjimą prie C ++ / CLI.

0
10 окт. Chris Charabaruk atsakymas, pateiktas spalio 10 d 2008-10-10 02:19 '08 at 2:19 AM 2008-10-10 02:19

Bandžiau šį sprendimą kodo projekte, kuris įterpia DLL: http://www.codeproject.com/Articles/528178/Load-DLL-From-Embedded-Resource

Ir jis puikiai dirbo.

0
15 июня '16 в 9:40 2016-06-15 09:40 atsakymą pateikė Chagbertas birželio 16 d. 16 val. 9:40 2016-06-15 09:40

Paprastai, norint atlikti susijungimą, kaip aprašyta, jums reikės tam tikros formos po kūrimo. Yra nemokamas įrankis „Eazfuscator“ („eazfuscator.blogspot.com/“), skirtas valdyti bytekodą, kuris taip pat tvarko surinkimo sintezę. Tai galite pridėti prie komandų eilutės su „Visual Studio“, kad sukompiliuotumėte savo statinius, tačiau jūsų kilometražo dydis priklausys nuo problemų, su kuriomis susidūrė bet kokie varžovų sujungimo scenarijai.

Taip pat galite patikrinti, ar NANT NANT rinkinys negali būti pastatytas, kad po surinkimo būtų sujungtos sąrankos, bet pats nežinau, kad pats NANT pasakys, ar funkcija yra įdėta, ar ne.

Taip pat yra daug „Visual Studio“ papildinių, kurie sujungs surinkimą kaip programos kūrimo dalį.

Arba, jei to nereikia automatiškai atlikti, yra keletas įrankių, pvz., „ILMerge“, kuri .net rinkinius sujungs į vieną failą.

Didžiausia problema, su kuria susidūriau sujungus agregatus, naudoja bet kokias panašias vardų vietas. Arba, dar blogiau, kreiptis į skirtingas tos pačios DLL versijas (mano problemos dažniausiai buvo susijusios su NUnit DLL failais).

0
28 окт. atsakymas pateikiamas wllmsaccnt Oct 28 2010-10-28 17:00 '10 17:00 val. 2010-10-28 17:00

Kiti klausimai apie žymes arba Užduoti klausimą