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.
Odpowiedzi:
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.
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:
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 )
źródło
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.
Oto mój oryginalny post na blogu: http://codeblog.larsholm.net/2011/06/embed-dlls-easily-in-a-net-assembly/
źródło
bytes
ma 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..dll
nazwa zawiera jakieś myślniki (tj.twenty-two.dll
), Zostaną one również zastąpione znakiem podkreślenia (tjtwenty_two.dll
.). Możesz zmienić ten wiersz kodu na ten:dllName = dllName.Replace(".", "_").Replace("-", "_");
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 #?
źródło
C++
pod linkiem. ILMerge działa również bardzo łatwo dla VB NET. Zobacz tutaj https://github.com/dotnet/ILMerge . Dzięki @ Shog9Tak, można łączyć pliki wykonywalne .NET z bibliotekami. Dostępnych jest wiele narzędzi do wykonania zadania:
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.
źródło
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.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:
Jeśli zestaw jest całkowicie niezarządzany, możesz zobaczyć ten link lub ten sposób ładowania takich bibliotek dll.
źródło
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).
źródło
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.
Install-Package ILRepack.MSBuild.Task
Oto prosta próbka, która łączy PrzykładAssemblyToMerge.dll z danymi wyjściowymi projektu.
źródło
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.).
źródło
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.
źródło
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:
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:
i po prostu zwróć null, jeśli przekazany zestaw nie należy do
IncludedAssemblies
.źródło
.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):
Odbywa się to bez zewnętrznego narzędzia.
Aby uzyskać więcej informacji, zobacz moją odpowiedź na to pytanie .
źródło
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 .
źródło
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):
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:
... i dodaj sam resolver gdzieś w klasie:
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:
źródło
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.
źródło
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).
źródło