|
Dynamiczne dołączanie bibliotek dll
Autor: Vnookality
Na grupie dyskusyjnej pl.comp.lang.c padło kiedyś pytanie: "... czy mogę jakoś korzystać z bibliotek dll bez tworzenia pliku *.lib i importowania go do projektu?". Rozwiązanie oczywiście jest i jest oczywiście lepsze od importowania *.lib'a. Po pierwsze taka biblioteka jest ładowana do pamięci wraz z głównym modułem programu. Jest to o tyle złe, że gdy mamy zbyt mało pamięci i ogromną ilość modułów *.dll do zaimportowania, to może jej w końcu nie wystarczyć, lub bardzo nieprzyjemnie spowalniać pracę programu i wraz z tym innych aplikacji. Zalet dynamicznego dołączania i zwalniania bibliotek dll to między innymi:
- lepsze zarządzanie pamięcią. Gdy biblioteka jest nam potrzebna, ładujemy ją, a gdy przestaje - zwalniamy ją po prostu z pamięci.
- możliwość umieszczania dll'i w dowolnym katalogu programu. Gdybyśmy użyli importowania lib'a biblioteka dll musiałaby znajdować się w głównym katalogu programu, co nie wszystkim może pasować.
- nie musimy tworzyć wspomnianych plików importowych. To bardzo przyspiesza tworzenie aplikacji i nie wymaga od nas używania innych dodatkowych programów takich jak implib.exe czy też impdef.exe.
Poniżej pokażę przykład takowej biblioteki. Jak je tworzyć? Trochę inaczej niż biblioteki z plikami importowymi. Tutaj musimy użyć Incremental linker'a. Inaczej naszej biblioteki nie będzie można załadować do pamięci. Oto przykładowy kod takiej biblioteki:
|
Unit1.cpp |
|
//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop
//---------------------------------------------------------------------------
extern "C" __declspec(dllexport) void __stdcall RunThisModule();
//---------------------------------------------------------------------------
int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void*)
{
return 1;
}
//---------------------------------------------------------------------------
void __stdcall RunThisModule()
{
ShowMessage("Hello!");
}
//---------------------------------------------------------------------------
| |
|
Powyższy przykład pokazuje Message'a z napisem "Hello". Jest to najprostsza biblioteka jaka przyszła mi do głowy. No, ale mniejsza z tym. Bibliotekę trzeba (to chyba jasne...) skompilować jako dll. Powiedzmy, że plik biblioteki nazywa się Tutorial.dll. Nazwa dll'a jest bardzo ważna! Sprawdź ją i najlepiej zapamiętaj lub zapisz.
Teraz czas na program, który wykorzysta naszą bibliotekę. Ten fragment jest najważniejszy. Od niego zależy, czy program po pierwsze załaduje bibliotekę i znajdzie naszą funkcję. Przyjrzyj się poniższemu przykładowi. Potem opiszę cały kod.
W pliku nagłówkowym (przed deklaracją klasy TForm):
|
Unit1.h |
|
typedef void __stdcall (*PROCRunThisModule)();
extern "C" void __stdcall RunThisModule();
|
|
W pliku źródłowym:
|
Unit1.cpp |
|
void __fastcall TForm1::Button1Click(TObject *Sender)
{
HINSTANCE NaszDLL;
NaszDLL = LoadLibrary("Tutorial.dll");
if (NaszDLL == NULL)
{
Application->MessageBox("Nie można załadować Biblioteki dll!","Błąd",
MB_OK | MB_ICONHAND);
}
else
{
PROCRunThisModule _RunThisModule =
(PROCRunThisModule)GetProcAddress(NaszDLL, "RunThisModule");
if (_RunThisModule == NULL)
{
Application->MessageBox("Nie znalazłem zdefiniowanej funkcji!","Błąd",
MB_OK | MB_ICONHAND);
}
else
{
_RunThisModule();
}
}
}
|
|
A teraz opis powyższego kodu. Najpierw tworzymy uchwyt dla naszej biblioteki, czyli w tym przypadku HINSTANCE NaszDLL. Następnie ładujemy bibliotekę dll (LoadLibrary()). Należy zauważyć, że przy ładowaniu dll'a można wprowadzić dowolną ścieżkę dostępu do dll'a. I ważne! Najpierw program próbuje załadować plik o zdefiniowanej nazwie z katalogu głównego programu, a jeżeli jej nie ma, to próbuje znaleźć ją w głównym katalogu Windows'a. Można się o tym przekonać, kasując nasz plik Tutorial.dll z katalogu głównego programu, a kopiując go do katalogu Windows'a. Efekt jest ten sam. Dalej sprawdzamy, czy biblioteka została załadowana. Jeżeli wartość jest równa NULL, zostaje pokazane okno z komunikatem o niepowodzeniu. Jeżeli jest inaczej, program sprawdza czy podana funkcja znajduje się w dll'u. Tak jak wyżej, jeżeli wartość jest równa NULL, zostaje pokazany komunikat. Jeżeli nie byłoby funkcji warunkowej if, program zwróciłby błąd "External exception". Lepiej wygląda jednak błąd zdefiniowany przez nas ;) Jeżeli jednak funkcja występuje, program wykonuje ją.
Bibliotekę zwalniamy funkcją FreeLibrary("Tutorial.dll"), którą najlepiej umieszczać zaraz po funkcji wywoływanej z dll'a. Jeżeli jest to jednak funkcja wywołująca okno nie modalne, należy pamiętać, że program będzie próbował zwolnić bibliotekę z pamięci mimo iż jest ona używana! W takim wypadku najlepiej deklarację uchwytu naszej biblioteki wstawić tuż pod nazwami plików nagłówkowych, a funkcję FreeLibrary w zdarzeniu OnClose() formy.
To by było na tyle. Jeżeli masz jakieś kłopoty, zawsze możesz napisać na mój e-mail: vnookality@poczta.fm lub vnookality@go2.pl. No i... szybkiego kompilowania i zera error'ów :)
| Wasze opinie: |
| Średnia ocena: 7.29/10 (34 głosów) |
|
| Liczba komentarzy: 10 (pokaż wszystkie) | Skomentuj !
|
| Autor: webster21 | Data dodania: 2007-06-05 |
| A ja mam takie pytanie. Jak mozna przekazywac zmienne do biblioteki?
np: wg artykulu:
_RunThisModule("to jest moja wiadomosc"); |
| Autor: _ | Data dodania: 2007-05-10 |
| D@nior ty jesteś pedałem!
|
| Autor: jerzozwierz | Data dodania: 2006-05-13 |
| stary uratowałeś mi życie, razem z twoją pracą i pc world komputer pokonałem bestie :) pozdro |
| Autor: mb | Data dodania: 2006-04-20 |
| Artykuł ok ale autor zapomniał o zwolnieniu uchwytów... |
| Autor: nowy :p | Data dodania: 2006-03-24 |
| Dobry artykuł bo prosty. Przydalby sie tez dla średnio zaawansowanych, np o typach wiadomosci do wyhookowania np WM_KEYBOARD (keylogger :D) albo jak wylapac wiadomosci z neta (chodzi mi o connect, read, write, disconnect itp), moglbym wtedy odczytywac co moje programki knują xD wiecej takich artykulow. plz new article ^^ thx |
| Autor: author... | Data dodania: 2006-03-15 |
| no ja nie uwazam aby ciezko bylo cos o DLLach znalezc, jak potrzebowalem to w mniej niz minute znalazlem. polecam strone www.gamedev.pl - jest glownie dla programistow gier, ale jest takze duzo innych artykulow |
| Autor: Zibi | Data dodania: 2006-02-28 |
| ten kod Borland powinien dołączać do plików demonstracyjnych...
Podziękowania dla autora za chęć dzielenia się wiedzą... |
|
|