Często w naszym programie zachodzi konieczność zastosowania zewnętrznych bibliotek
do różnych celów np do obsługi czegoś tam ...
tak tak wiem zacząłem z dziwnej strony ...
niemniej zaraz wszystko stanie się jasne ....
W zasadzie mamy w przypadku używania zewnętrznych bibliotek x.dll dwie możliwości:
1. Dodajemy w projekcie Odwołanie do biblioteki i we właściwościach odwołania (reference)
zaznaczamy żeby była wykonana kopia lokalna
- spowoduje to że po kompilacji do folderu zostanie zapisany plik dll i będzie można tak jej
używać z pliku dll z folderu programu .
Rozwiązanie jest dobre i często się takie stosuje. Niemniej czasem jest mało wygodne , czasem chcemy też by nasz program nie zawierał zbyt wielu plików ....
Co możemy więc z tym zrobić ??
-- ano całkiem sporo
W tym poradniku zajmiemy się osadzaniem bibliotek dll w pliku exe.
Powiecie pewnie jaki ma to cel i sens ....
No spory - zwłaszcza gdy chcemy by nasz program był przenośny zobaczmy więc co tak naprawdę nam daje ....
-------- ZALETY - ułatwia dystrybucję programu wśród użytkowników jeden plik - zamiast wielu
- wymagane pliki dll nie zostaną przypadkiem pominięte przez użytkownika ,
- w przypadku niektórych bibliotek może się pojawić nowa wersja - użytkownik będzie
wolał pobrać jeden plik niż np ręcznie zmieniać pliki dll.
Jak widać to dużo , ale metoda ma też wadę może w dobie dzisiejszych komputerów nie aż tak
istotną , ale jednak...
- wymaga więcej pracy od programisty i wymusza podjęcie dodatkowych kroków w celu scalenia plików, a keżde nowe wydanie dla danego dll jeśli jest to konieczne w aplikacji wymaga jej przepakowanie ...
----------------------------------------------------------------------------------------------
Osadzanie plików *.dll jest używane przez programy instalatorów powiecie , przecież też są w jednym pliku. Tak to prawda , ale nasza aplikacja nie wymaga instalacji jest za mała , po za tym
przecież nie robimy tradycyjnego śmietnika na dysku rozrzucając pliki po całym dysku i rejestrze.
Zróbmy to tak jak powinno się to robić i jak to było wykonywane w porządnych systemach ...
Dobrze .... zatem stwórzmy nowy projekt i nazwijmy go ... wbudowana_biblioteka
następnie jakieś biblioteki :
a niech to będzie np System.Windows.Forms.Ribbon35.DLL z
http://officeribbon.codeplex.com oraz System.Data.SQLite.DLL z
http://system.data.sqlite.org to dobra okazja bowiem pierwsza zawiera pakiet komponentów, a druga obsługę bazy danych
i sie różnią - pierwsza jest zarządzalna , a druga nie
oznacza to że do pierwszej poza wywołaniem funkcji przekazujemy parametry , a z drugiej tylko
wywołujemy funkcje. Dobra mamy już nasz projekt i biblioteki. i Co teraz ??
A no nic ...
gdy już mamy nasz projekt dodajemy odwołanie do naszych bibliotek.
jest to banalnie proste , klikamy RMB na Odwołania i z meny wybieramy Dodaj odwołanie
pojawi się nam okienko:
gdzie w zakładce przeglądaj wybieramy nasze biblioteki po kolei i klikamy OK ....
Odwołania mamy z głowy ... pojawiły się ...
W zasadzie od teraz możemy już używać w naszym programie już bibliotek o czym wspomniałem na początku
wymaga to tylko dodania bibliotek do pliku wykonywalnego ... (do ProgDira) co możemy ja wspominałem
zrobić we właściwościach odwołania :
zmieniając wartość pola Kopia lokalna na true -- co spowoduje skopiowanie pliku dll do folderu kompilacji (dołączenie do programu).
Ale nas to nie interesuje ....mu chcemy nasze biblioteki zaszyć w pliku exe....
Zatem teraz musimy nasze pliki dll dodać do projektu...
Możemy to zrobić na 2 sposoby...
1. kliknąć RMB na nazwie projektu i wybrać dodaj - istniejący element lub Shift-Alt-A i wybrać nasze pliki dll
2. Przeciągnąć je na projekt np z pulpitu lub lokalizacji projektu i upuścić (drag&drop)
ma to wyglądać tak:
Teraz będzie trudniej ....
Przede wszystkim w odwołaniu do biblioteki kopia lokalna ma być false -- co widać wyżej .... (nie będziemy kopiować bibliotek)
Teraz klikamy na naszych plikach DLL w eksploratorze projektu i w ich właściwościach .....
Dla obu plików .dll zmieniamy wartość pola Akcja Kompilacji na Zasób osadzony .....
ma to wyglądać dokładnie jak widzicie wyżej...
Uffff ... to tyle ....
no nie żartowałem ... fakt po kompilacji nasze biblioteki zostaną dołączone do pliku exe, ale nie będą używane i nie zadziała nasz program na kompie bez tych bibliotek ....
Zróbmy więc cokolwiek co zawierają nasze libsy na formie1.
np tak .... dodamy panel z biblioteki Ribon
i sami sprawdźcie ... po kompilacji że bez bibliotek wasz program nie działa .... no bo niby jak co ..
przecież poza tym ze dodaliśmy je do pliku program nie wie gdzie są i jak je użyć ....
no to do roboty.....
Nasze zadanie jest proste ... musimy podczas uruchomienia programu wypakować biblioteki i załadować do programu ...
Szukamy w projekcie pliku Program.cs (zawiera on podstawową klase naszego programu) i otwieramy go:
tam znajdujemy funkcję main()
język c
Musisz się zalogować, aby zobaczyć kod źródłowy. Tylko zalogowani użytkownicy mogą widzieć kod.
jak widać całość jest jasna ...
i dopisujemy ładowanie naszych dll do ram....
co powinno wyglądać tak
język c
Musisz się zalogować, aby zobaczyć kod źródłowy. Tylko zalogowani użytkownicy mogą widzieć kod.
Używamy jak widać metody PaczkaDll.Load by załadować nasze wbudowane biblioteki do pamięci RAM. Zwróćcie też uwagę na format ciągu zasobów:
Wbudowana_biblioteka.System.Data.SQLite.dllCiąg ten to jakby adres naszego zasobu. Zawiera nazwę naszego projektu i pliku DLL. trzeba na to uważać gdyż jeśli chcemy np dodać biblioteki w folderze np DLLe to ta nazwa folderu musi byc też uwzględniona w adresie. Ale tu dodajemy tylko czyste pliki dll... niemniej jeśli trzeba to powinno to wyglądać tak:
nazwa_aplikacji.nazwa_folderu.System.Data.SQLite.dll zdarzenie AppDomain.CurrentDomain.AssemblyResolve.. jest przydatne w wypadku gdy biblioteki nie mogą być zlokalizowane przez aplikację do dystrybucji. AssemblyResolve wywołuję żądanie plików DLL
których brakuje. Musimy więc jej powiedzieć że nasze biblioteki są w pamięci RAM, w tym celu użyjemy metody PaczkaDll.Get by pobrać biblioteki z pamięci i przekazać je do AssemblyResolve, który obsłuży całą resztę ...
a więc dopiszmy jeszcze kawałek kodu pod funkcją main()
język c
Musisz się zalogować, aby zobaczyć kod źródłowy. Tylko zalogowani użytkownicy mogą widzieć kod.
a cały nasz plik Program.cs powinien wyglądać np tak:
język c
Musisz się zalogować, aby zobaczyć kod źródłowy. Tylko zalogowani użytkownicy mogą widzieć kod.
I to by było na tyle ?? -
tak i nie ... gdyż potrzeba nam jeszcze stworzyć klasę PaczkaDll.
w tym celu do naszego projektu dodajemy nową klasę (Shift-Alt-C) i nazywamy ją PaczkaDll.cs
otwieramy plik i w nim umieszczamy kod:
język c
Musisz się zalogować, aby zobaczyć kod źródłowy. Tylko zalogowani użytkownicy mogą widzieć kod.
Powyższy kod zawiera metody ładowania plików DLL które będą używane z .Net
A musimy wiedzieć że mamy dwa typy plików Dll
- Zarządzane DLL
- Niezarządzalne DLL lub Mixed Code DLL
dlatego też procedury ładowania sa odmienne ...
W przypadku zarządzalnych DLL procedura ładowania jest prosta i można ją zrealizować np tak:
język c
Musisz się zalogować, aby zobaczyć kod źródłowy. Tylko zalogowani użytkownicy mogą widzieć kod.
Ale biblioteki niezarządzalnej nie możemy załadować bezpośrednio do tablicy byte[] tak jak zarządzalnej
tu musimy:
1. najpierw załadować osadzoną bibliotekę do tablicy byte[]
2. zapisać zawartość tablicy byte[] do fizycznego pliku i przechować w folderze temp
3. użyć metody loadFile() by załadować plik do pamieci
co opisałem w komentarzach w kodzie PaczkaDLL.. która to będzie wstępnie ładować wymagane biblioteki DLL i przechowywać je wewnątrz "Słownika", a gdy nastąpi ewent AssembyResolve metoda PaczkaDll.Get()
zwróci żądaną bibliotekę.
Miłej zabawy z osadzaniem plików....