Osadzanie bibliotek DLL w skompilowanym pliku wykonywalnym

618

Czy można osadzić wcześniej istniejącą bibliotekę DLL w skompilowanym pliku wykonywalnym w języku C # (tak, że masz tylko jeden plik do dystrybucji)? Jeśli to możliwe, jak można to zrobić?

Zwykle nie mam nic przeciwko pozostawieniu bibliotek DLL na zewnątrz i skonfigurowaniu programu do obsługi wszystkiego, ale było kilka osób w pracy, które mnie o to pytały i szczerze mówiąc nie wiem.

Merus
źródło
Polecam sprawdzenie narzędzia .NETZ, które kompresuje również zestaw według wybranego schematu: http://madebits.com/netz/help.php#single
Nathan Baulch
2
Jest to możliwe, ale skończysz na dużym pliku wykonywalnym (Base64 zostanie użyty do zakodowania twojej biblioteki DLL).
Paweł Dyda
Oprócz ILMerge , jeśli nie chcesz zawracać sobie głowy przełącznikami wiersza poleceń, naprawdę polecam ILMerge-Gui . To projekt typu open source, naprawdę dobrze!
tyron,
2
@ PawełDyda: Możesz osadzić surowe dane binarne w obrazie PE (patrz RCDATA ). Transformacja nie jest wymagana (ani zalecana).
Widoczny

Odpowiedzi:

761

Zdecydowanie polecam użyć Costura.Fody - zdecydowanie najlepszy i najłatwiejszy sposób na osadzenie zasobów w swoim zestawie. Jest dostępny jako pakiet NuGet.

Install-Package Costura.Fody

Po dodaniu go do projektu, automatycznie osadza wszystkie odniesienia skopiowane do katalogu wyjściowego do głównego zestawu. Możesz wyczyścić osadzone pliki, dodając cel do swojego projektu:

Install-CleanReferencesTarget

Będziesz także mógł określić, czy dołączyć pdb, wykluczyć niektóre zespoły, czy wyodrębnić zespoły w locie. O ile mi wiadomo, obsługiwane są również niezarządzane zestawy.

Aktualizacja

Obecnie niektóre osoby próbują dodać obsługę DNX .

Aktualizacja 2

Aby uzyskać najnowszą wersję Fody, musisz mieć MSBuild 16 (więc Visual Studio 2019). Fody w wersji 4.2.1 wykona MSBuild 15. (odniesienie: Fody jest obsługiwany tylko w MSBuild 16 i nowszych. Aktualna wersja: 15 )

Matthias
źródło
79
Dziękuję za tę niesamowitą sugestię. Zainstaluj pakiet i gotowe. Domyślnie kompresuje nawet zespoły.
Daniel
9
Nienawidzę być „ja też”, ale ja też - to zaoszczędziło mi dużo bólu głowy! Dziękuję za rekomendację! To pozwoliło mi spakować wszystko, czego potrzebuję do redystrybucji w jednym pliku exe, a teraz jest ono mniejsze niż oryginalne pliki exe i dll zostały połączone ... Używam tego tylko od kilku dni, więc nie mogę powiedzieć, że „ Po sprawdzeniu, ale z wyjątkiem wyskakiwania wszystkiego, co wyskakuje źle, widzę, że staje się to zwykłym narzędziem w moim zestawie narzędzi. To po prostu działa!
mattezell,
19
To jest spoko. Ale jest wada: zestaw generowany w systemie Windows nie jest już binarnie zgodny z mono Linuksem. Oznacza to, że nie można wdrożyć zestawu bezpośrednio w systemie Linux mono.
Tyler Long,
7
To jest urocze! Jeśli używasz vs2018, nie zapomnij pliku FodyWeavers.xml, który będzie znajdować się w katalogu głównym projektu.
Alan Deep
4
Jako uzupełnienie ostatniego komentarza: dodaj plik FodyWeavers.xml z następującą zawartością do swojego projektu: <? Xml version = "1.0" encoding = "utf-8"?> <Weavers VerifyAssembly = "true"> <Costura /> </Weavers>
HHenn
88

Po prostu kliknij prawym przyciskiem myszy projekt w Visual Studio, wybierz Właściwości projektu -> Zasoby -> Dodaj zasób -> Dodaj istniejący plik… I dołącz poniższy kod do pliku App.xaml.cs lub równoważnego.

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

Oto mój oryginalny post na blogu: http://codeblog.larsholm.net/2011/06/embed-dlls-easily-in-a-net-assembly/

Lars Holm Jensen
źródło
6
Możesz mieć to zachowanie od razu po wyjęciu z pudełka. Sprawdź moją odpowiedź stackoverflow.com/a/20306095/568266
Matthias
4
Ważne jest również, aby zanotować NIESAMOWITE przydatny komentarz na swoim blogu od AshRowe: jeśli masz zainstalowany niestandardowy motyw, spróbuje on rozwiązać zespół PresentationFramework.Theme, który ulega awarii i pali się! Zgodnie z sugestią AshRowe, możesz po prostu sprawdzić, czy dllName zawiera PresentationFramework w taki sposób: if (dllName.ToLower (). Zawiera („prezentacjaframework”)) zwraca null;
YasharBahman
4
Dwa komentarze na ten temat. Po pierwsze: powinieneś sprawdzić, czy bytesma wartość null, a jeśli tak, zwróć tam wartość null. Możliwe, że dll w końcu nie ma w zasobach. Po drugie: Działa to tylko wtedy, gdy sama klasa nie ma „użycia” do czegokolwiek z tego zestawu. W przypadku narzędzi wiersza poleceń musiałem przenieść mój rzeczywisty kod programu do nowego pliku i stworzyć mały nowy program główny, który właśnie to robi, a następnie wywołuje oryginalny main w starej klasie.
Nyerguds
2
Zaletą tego podejścia jest to, że nie polega on na instalowaniu zewnętrznych bibliotek w celu osiągnięcia pożądanej funkcjonalności. Minusem tego podejścia jest to, że przydaje się tylko w przypadku zarządzanych bibliotek DLL - biblioteki DLL międzyoperacyjne (przynajmniej tak dalece, jak idzie moje testowanie) nie uruchamiają zdarzenia assemblyresolve, a nawet jeśli zrobiły to Assembly.Load (<bajty niektórych interakcji .dll>) nie osiąga pożądanego efektu na drodze. stackoverflow.com/questions/13113131/… Tylko moje 2c w tej sprawie
XDS
3
Na wypadek, gdyby ktoś napotkał mój problem: jeśli .dllnazwa zawiera jakieś myślniki (tj. twenty-two.dll), Zostaną one również zastąpione znakiem podkreślenia (tj twenty_two.dll.). Możesz zmienić ten wiersz kodu na ten:dllName = dllName.Replace(".", "_").Replace("-", "_");
Micheasz Vertal
87

Jeśli faktycznie są one zarządzanymi zespołami, możesz użyć ILMerge . W przypadku natywnych bibliotek DLL będziesz mieć trochę więcej pracy do zrobienia.

Zobacz także: W jaki sposób można połączyć bibliotekę DLL systemu Windows w exe aplikacji C #?

Shog9
źródło
Jestem zainteresowany natywnym scalaniem DLL, czy są jakieś materiały?
Baiyan Huang
5
Zobacz także: stackoverflow.com/questions/108971/...
Milan Gardian,
@BaiyanHuang spójrz na github.com/boxedapp/bxilmerge , pomysł polega na stworzeniu „ILMerge” dla rodzimych bibliotek DLL.
Artem Razin
Programiści VB NET tacy jak ja nie boją się tego C++pod linkiem. ILMerge działa również bardzo łatwo dla VB NET. Zobacz tutaj https://github.com/dotnet/ILMerge . Dzięki @ Shog9
Ivan Ferrer Villa
26

Tak, można łączyć pliki wykonywalne .NET z bibliotekami. Dostępnych jest wiele narzędzi do wykonania zadania:

  • ILMerge to narzędzie, którego można użyć do scalenia wielu zestawów .NET w jeden zestaw.
  • Mono mkbundle , pakuje exe i wszystkie zestawy z libmono w jeden pakiet binarny.
  • IL-Repack jest alternatywą FLOSS do ILMerge, z kilkoma dodatkowymi funkcjami.

Ponadto można to połączyć z Mono Linkerem , który usuwa nieużywany kod i dlatego zmniejsza wynikowy zestaw.

Inną możliwością jest użycie .NETZ , który nie tylko pozwala na kompresowanie zestawu, ale także może spakować pliki dll bezpośrednio do exe. Różnica w stosunku do wyżej wymienionych rozwiązań polega na tym, że .NETZ nie łączy ich, pozostają one oddzielnymi zespołami, ale są pakowane w jedno opakowanie.

.NETZ to narzędzie typu open source, które kompresuje i pakuje pliki wykonywalne Microsoft .NET Framework (EXE, DLL) w celu ich zmniejszenia.

Konstabl
źródło
NETZ wydaje się zniknąć
Rbjz
Wow - myślałem, że w końcu go znalazłem, a potem przeczytałem ten komentarz. Wygląda na to, że zniknął całkowicie. Czy są jakieś widelce?
Mafii,
Cóż, właśnie przeniósł się do GitHub i nie jest już powiązany z witryną ... więc „odszedł całkowicie” to przesada. Najprawdopodobniej nie jest już obsługiwany, ale nadal tam jest. Zaktualizowałem link.
Bobby,
20

ILMerge może łączyć zespoły w jeden pojedynczy zespół, pod warunkiem, że zespół ma tylko zarządzany kod. Możesz użyć aplikacji wiersza polecenia lub dodać odwołanie do pliku exe i scalić programowo. W przypadku wersji GUI dostępny jest Eazfuscator , a także .Netz, które są bezpłatne. Płatne aplikacje to BoxedApp i SmartAssembly .

Jeśli musisz scalić zestawy z niezarządzanym kodem, sugerowałbym SmartAssembly . Nigdy nie miałem czkawki z SmartAssembly, ale ze wszystkimi innymi. Tutaj może osadzić wymagane zależności jako zasoby w głównym pliku exe.

Możesz zrobić to wszystko ręcznie, nie martwiąc się, czy asemblerem zarządzany jest tryb mieszany, osadzając dll w swoich zasobach, a następnie polegając na asemblerze AppDomain ResolveHandler. Jest to kompleksowe rozwiązanie, przyjmując najgorszy przypadek, tj. Zespoły z niezarządzanym kodem.

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

Kluczem tutaj jest zapis bajtów do pliku i ładowanie z jego lokalizacji. Aby uniknąć problemu z kurczakiem i jajkiem, musisz upewnić się, że deklarujesz moduł obsługi przed uzyskaniem dostępu do zespołu i że nie masz dostępu do elementów zestawu (lub tworzenia instancji wszystkiego, co ma do czynienia z zespołem) wewnątrz części ładowania (rozwiązywania zespołu). Upewnij się również, GetMyApplicationSpecificPath()czy nie ma katalogu tymczasowego, ponieważ pliki tymczasowe mogłyby zostać usunięte przez inne programy lub przez ciebie (nie dlatego, że zostaną usunięte, gdy twój program uzyskuje dostęp do biblioteki dll, ale przynajmniej jest to uciążliwe. AppData jest dobra Lokalizacja). Zauważ też, że musisz pisać bajty za każdym razem, nie możesz załadować z lokalizacji, ponieważ biblioteka DLL już tam znajduje się.

W przypadku bibliotek DLL zarządzanych nie trzeba pisać bajtów, ale ładować bezpośrednio z lokalizacji biblioteki DLL lub po prostu czytać bajty i ładować zestaw z pamięci. Tak lub mniej:

    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.

Jeśli zestaw jest całkowicie niezarządzany, możesz zobaczyć ten link lub ten sposób ładowania takich bibliotek dll.

nawfal
źródło
Pamiętaj, że „Kompilacja działania” zasobu musi być ustawiona na „Zasób osadzony”.
Mavamaarten
@Mavamaarten Niekoniecznie. Jeśli zostanie on wcześniej dodany do Resources.resx projektu, nie musisz tego robić.
Nyerguds
2
EAZfuscator jest teraz komercyjny.
Telemat
16

Fragment Jeffrey Richter jest bardzo dobra. Krótko mówiąc, dodaj bibliotekę jako zasoby osadzone i dodaj wywołanie zwrotne, zanim cokolwiek innego. Oto wersja kodu (znaleziona w komentarzach na jego stronie), którą umieściłem na początku metody Main dla aplikacji konsolowej (po prostu upewnij się, że wszystkie wywołania, które korzystają z biblioteki, są inne niż Main).

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);
            }
        };
Steve
źródło
1
Trochę to zmieniłem, wykonałem robotę, kolego tnx!
Sean Ed-Man
Projekt libz.codeplex.com korzysta z tego procesu, ale zrobi też kilka innych rzeczy, takich jak zarządzanie programem obsługi zdarzeń i specjalny kod, aby nie złamać „ Katalogów ram zarządzanych rozszerzeń ” (które same przez siebie ten proces by się zepsuł)
Scott Chamberlain
To wspaniale!! Dzięki @Steve
Ahmer Afzal
14

Aby rozwinąć odpowiedź @ Bobby powyżej. Możesz edytować plik .csproj, aby użyć IL-Repack do automatycznego pakowania wszystkich plików w jeden zestaw podczas kompilacji.

  1. Zainstaluj pakiet nuget ILRepack.MSBuild.Task za pomocą Install-Package ILRepack.MSBuild.Task
  2. Edytuj sekcję AfterBuild w .csproj

Oto prosta próbka, która łączy PrzykładAssemblyToMerge.dll z danymi wyjściowymi projektu.

<!-- 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>
Josh
źródło
1
Składnia IL-Repack uległa zmianie, sprawdź plik README.md znajdujący się na połączonym repozytorium github ( github.com/peters/ILRepack.MSBuild.Task ). Ten sposób był jedynym, który działał dla mnie i mogłem użyć znaku wieloznacznego, aby dopasować wszystkie biblioteki dll, które chciałem dołączyć.
Seabass77
8

Możesz dodać biblioteki DLL jako zasoby osadzone, a następnie pozwolić programowi rozpakować je w katalogu aplikacji podczas uruchamiania (po sprawdzeniu, czy już tam są).

Pliki instalacyjne są jednak tak łatwe do zrobienia, że ​​nie sądzę, by było warto.

EDYCJA: Ta technika byłaby łatwa w przypadku zespołów .NET. W przypadku bibliotek DLL innych niż .NET byłoby o wiele więcej pracy (trzeba by dowiedzieć się, gdzie rozpakować pliki i zarejestrować je itd.).

MusiGenesis
źródło
Oto świetny artykuł, który wyjaśnia, jak to zrobić: codeproject.com/Articles/528178/Load-DLL-From-Embedded-Resource
niebieskawy
8

Kolejnym produktem, który potrafi poradzić sobie z tym elegancko, jest SmartAssembly, na SmartAssembly.com . Ten produkt oprócz połączenia wszystkich zależności w jedną bibliotekę DLL (opcjonalnie) zaciemni kod, usunie dodatkowe metadane, aby zmniejszyć rozmiar pliku wynikowego, a także może faktycznie zoptymalizować IL w celu zwiększenia wydajności środowiska wykonawczego.

Istnieje także rodzaj globalnej obsługi wyjątków / raportowania, który dodaje do twojego oprogramowania (w razie potrzeby), który może być przydatny. Wierzę, że ma również interfejs API wiersza polecenia, dzięki czemu możesz włączyć go do procesu kompilacji.

Nathan
źródło
7

Ani podejście ILMerge, ani Lars Holm Jensen obsługujący zdarzenie AssemblyResolve nie będą działać dla hosta wtyczek. Powiedz, że wykonywalny H ładuje dynamicznie zestaw P i uzyskuje do niego dostęp poprzez interfejs IP zdefiniowany w oddzielnym zestawie. Aby osadzić IP w H , potrzebna jest niewielka modyfikacja kodu Larsa:

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

Sztuczka związana z powtarzającymi się próbami rozwiązania tego samego zestawu i zwrócenia istniejącego zamiast tworzenia nowej instancji.

EDYCJA: Aby nie zepsuć serializacji .NET, pamiętaj, aby zwrócić wartość null dla wszystkich zestawów, które nie są osadzone w twoim, w ten sposób zachowując domyślne zachowanie. Możesz uzyskać listę tych bibliotek poprzez:

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

i po prostu zwróć null, jeśli przekazany zestaw nie należy do IncludedAssemblies.

Ant_222
źródło
Przepraszamy za opublikowanie go jako odpowiedzi, a nie komentarza. Nie mam prawa komentować odpowiedzi innych.
Ant_222,
5

.NET Core 3.0 natywnie obsługuje kompilację do pojedynczego pliku .exe

Ta funkcja jest włączona przez użycie następującej właściwości w pliku projektu (.csproj):

    <PropertyGroup>
        <PublishSingleFile>true</PublishSingleFile>
    </PropertyGroup>

Odbywa się to bez zewnętrznego narzędzia.

Aby uzyskać więcej informacji, zobacz moją odpowiedź na to pytanie .

Marcell Toth
źródło
3

Może się to wydawać uproszczone, ale WinRar daje możliwość kompresji kilku plików do samorozpakowującego się pliku wykonywalnego.
Ma wiele konfigurowalnych opcji: ikona końcowa, wypakuj pliki do podanej ścieżki, plik do wykonania po rozpakowaniu, niestandardowe logo / teksty dla wyskakującego okienka wyświetlanego podczas wyodrębniania, w ogóle nie wyskakujące okno, tekst umowy licencyjnej itp.
Może być przydatny w niektórych przypadkach .

Ivan Ferrer Villa
źródło
Sam system Windows ma podobne narzędzie o nazwie iexpress. Oto samouczek
Ivan Ferrer Villa
2

Używam kompilatora csc.exe wywoływanego ze skryptu .vbs.

W skrypcie xyz.cs dodaj następujące wiersze po dyrektywach (mój przykład dotyczy Renci SSH):

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"

Znaczniki ref, res i ico zostaną pobrane przez poniższy skrypt .vbs w celu utworzenia polecenia csc.

Następnie dodaj wywoływacz resolvera zestawu w Main:

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

... i dodaj sam resolver gdzieś w klasie:

    static Assembly CurrentDomain_AssemblyResolve (nadawca obiektu, Argumenty ResolveEventArgs)
    {
        Łańcuch nazwa_zasobu = nowa nazwa_zespołu (args.Name). Nazwa + ".dll";

        using (var stream = Assembly.GetExecutingAssembly (). GetManifestResourceStream (resourceName))
        {
            Byte [] assemblyData = new Byte [stream.Length];
            stream.Read (assemblyData, 0, assemblyData.Length);
            return Assembly.Load (assemblyData);
        }

    }

Nazywam skrypt vbs, aby pasował do nazwy pliku .cs (np. Ssh.vbs szuka ssh.cs); dzięki temu uruchamianie skryptu wiele razy jest dużo łatwiejsze, ale jeśli nie jesteś idiotą takim jak ja, ogólny skrypt może pobrać docelowy plik .cs z przeciągania i upuszczania:

    Dim name_, oShell, fso
    Ustaw oShell = CreateObject („Shell.Application”)
    Ustaw fso = CreateObject („Scripting.fileSystemObject”)

    „WEŹ NAZWĘ SKRYPTU VBS JAKO NAZWĘ PLIKU CELOWEGO
    „#############################################################################
    name_ = Split (wscript.ScriptName, ".") (0)

    „POBIERZ NAZWY ZEWNĘTRZNYCH DLL I IKONY Z PLIKU .CS
    „####################################################################### ######
    Stała OPEN_FILE_FOR_READING = 1
    Ustaw objInputFile = fso.OpenTextFile (name_ & ".cs", 1)

    „PRZECZYTAJ WSZYSTKO W MIEJSCU
    „#############################
    inputData = Split (objInputFile.ReadAll, vbNewline)

    Dla każdego strData w inputData

        jeśli pozostało (strData, 7) = "// + ref>", to 
            csc_references = csc_references & "/ reference:" & trim (replace (strData, "// + ref>", "")) & ""
        koniec jeśli

        jeśli pozostało (strData, 7) = "// + res>", to 
            csc_resources = csc_resources & "/ resource:" & trim (replace (strData, "// + res>", "")) & ""
        koniec jeśli

        jeśli pozostało (strData, 7) = "// + ico>", to 
            csc_icon = "/ win32icon:" & trim (replace (strData, "// + ico>", "")) & ""
        koniec jeśli
    Kolejny

    objInputFile.Close


    „SKompiluj plik
    „################
    oShell.ShellExecute "c: \ windows \ microsoft.net \ framework \ v3.5 \ csc.exe", "/ warn: 1 / target: exe" i csc_references & csc_resources & csc_icon & "" & name_ & ".cs" , „”, „runas”, 2


    WScript.Quit (0)
Mark Llewellyn
źródło
0

Utworzenie hybrydowego zestawu natywnego / zarządzanego w języku C # jest możliwe, ale nie takie proste. Gdybyś zamiast tego używał C ++, byłoby to o wiele łatwiejsze, ponieważ kompilator Visual C ++ może tworzyć zespoły hybrydowe równie łatwo, jak wszystko inne.

O ile nie masz ścisłego wymogu wyprodukowania zestawu hybrydowego, zgodziłbym się z MusiGenesis, że nie jest to warte zachodu z C #. Jeśli musisz to zrobić, możesz zamiast tego przejść do C ++ / CLI.

Chris Charabaruk
źródło
0

Zasadniczo potrzebujesz jakiejś formy narzędzia po kompilacji, aby wykonać scalanie zespołu, tak jak to opisujesz. Istnieje bezpłatne narzędzie o nazwie Eazfuscator (eazfuscator.blogspot.com/), które jest przeznaczone do manipulacji kodem bajtowym, która obsługuje także scalanie zestawu. Możesz dodać to do wiersza poleceń po kompilacji w programie Visual Studio, aby scalić swoje zespoły, ale twój przebieg będzie się różnił z powodu problemów, które pojawią się w każdym nietypowym scenariuszu scalania zespołu.

Możesz również sprawdzić, czy kompilacja czyni nieistotność NANT ma możliwość scalania zestawów po zbudowaniu, ale sam nie znam wystarczająco NANT, aby stwierdzić, czy funkcjonalność jest wbudowana, czy nie.

Istnieje również wiele wtyczek Visual Studio, które wykonają scalanie zestawu w ramach budowania aplikacji.

Alternatywnie, jeśli nie trzeba tego robić automatycznie, istnieje wiele narzędzi, takich jak ILMerge, które scalą zespoły .net w jeden plik.

Największym problemem, jaki miałem przy scalaniu zestawów, jest to, że używają podobnych przestrzeni nazw. Lub gorzej, odwołaj się do różnych wersji tego samego dll (moje problemy były ogólnie z plikami dll NUnit).

wllmsaccnt
źródło
1
Eazfuscator zadzwoni do IlMerge, AFAIK.
Bobby
+1 Bobby. Powinienem to pamiętać. Wszystko, co robi dla ciebie Eazfucator, to streszczenie rzeczywistych wywołań do ILMerge za pomocą bardziej ogólnego pliku konfiguracyjnego.
wllmsaccnt