2015-09-28 8 views
6

Ktoś wie, czy można go z wdziękiem przetestować i obsłużyć brakujący plik .dll w aplikacji Delphi? Na przykład, mój kod ma tę deklarację funkcję:możliwe do obsługi brakującego pliku dll z wdziękiem w aplikacji Delphi?

function KFUNC(Arg1, Arg2, Arg3, Arg4: DWord): longint stdcall; external 'KL2DLL32.DLL' name '[email protected]'; 

... co oczywiście wymaga pliku dll KL2DLL32.DLL można znaleźć w systemie, w przeciwnym razie moja aplikacja przyzwyczajenie rozpocząć. Zastanawiam się, czy istnieje inny sposób kodowania tego, więc moja aplikacja może przetestować istnienie pliku dll, a następnie obsługiwać odpowiednio. Oczywiście, celem byłoby, aby moja aplikacja wciąż zaczynała się normalnie, nawet jeśli nie ma pliku DLL. Dzięki.

+1

Użyj funkcji LoadLibrary i uzyskaj adres procedury. –

Odpowiedz

4

Gdy funkcja zostanie zadeklarowana w ten sposób, program nie może nic zrobić z brakującą biblioteką DLL. System operacyjny próbuje rozwiązać zaimportowaną funkcję DLL, zanim jakikolwiek fragment kodu twojego programu zacznie się uruchamiać, więc nie ma kodu, który można by napisać, który mógłby coś z tym zrobić.

Jednak od Delphi 2010 można zmienić deklarację funkcji, aby korzystać z nowej funkcji opóźnionego ładowania . Dodaj dyrektywę delayed do końca deklaracji:

function KFUNC(Arg1, Arg2, Arg3, Arg4: DWord): longint stdcall; 
    external 'KL2DLL32.DLL' name '[email protected]' delayed; 

Jeśli używasz starszej wersji Delphi, to jedyną opcją jest, aby załadować biblioteki DLL i funkcji w czasie wykonywania, a następnie obsługiwać błędy.

Inną korzyścią wynikającą z opóźnienia jest to, że istnieją funkcje SetDliNotifyHook2 i SetDliFailureHook2, które pozwalają na przypisanie haków, aby można było odpowiednio obsługiwać powiadomienia i awarie ładowania w czasie wykonywania.
Tak więc, jeśli dana biblioteka DLL, a nawet dana funkcja, nie zostanie znaleziona w środowisku wykonawczym, można zarejestrować błąd, nawet zastąpić go innym uchwytem DLL lub wskaźnikiem funkcji, aby spełnić ładunek.

Obie opcje są bardziej szczegółowo omówione w another question centering on using a DLL only when required.

+5

Funkcja 'delayed' jest po prostu opcją kompilatora/RTL dla funkcji' LoadLibrary() 'i' GetProcAddress() '. Inną zaletą używania opcji 'delayed' jest to, że istnieją funkcje' SetDliNotifyHook2() 'i' SetDliFailureHook2() ', które umożliwiają przypisanie hooków, aby można było odpowiednio obsługiwać powiadomienia i awarie ładowania w czasie wykonywania. Tak więc, jeśli dana biblioteka DLL lub nawet dana funkcja nie zostanie znaleziona w środowisku wykonawczym, można zarejestrować błąd, nawet zastąpić go innym uchwytem DLL lub wskaźnikiem funkcji, aby spełnić ładunek. –

11

Twoje wyniki importu są powiązane z funkcją, która jest nazywana czasem ładowania lub niejawnym łączeniem. To plik wykonywalny zawiera metadane, które nakazują programowi ładującemu system operacyjny załadowanie biblioteki DLL, a następnie powiązanie z nazwanymi funkcjami. Jeśli ten proces łączenia w czasie ładowania zakończy się niepowodzeniem, nie można załadować pliku wykonywalnego.

Masz kilka opcji, aby uniknąć łączenia w czasie ładowania, a tym samym pozwolić programowi być odpornym na łączenie awarii.

Delay-loading DLL

Dodaj dyrektywę delayed do importu funkcji. Dokumentacja mówi:

Aby opóźnić załadowanie biblioteki zawierającej funkcję moment funkcja jest rzeczywiście potrzebne, dołącz opóźnioną dyrektywę do funkcji importowanej:

function ExternalMethod(const SomeString: PChar): Integer; stdcall; 
    external 'cstyle.dll' delayed; 

opóźnione, zapewnia biblioteka, która zawiera zaimportowaną funkcję , nie jest ładowana podczas uruchamiania aplikacji, ale raczej po pierwszym wywołaniu funkcji dla tej funkcji.

Dokumentacja zawiera innych przydatnych tematów, które wykraczają w sposób bardziej szczegółowy, a pokrycie sposobu obsługi błędów:

Explicit załadunek i wiążących się z DLL

Dyrektywa delayed jest jedynie zwięzłym sposobem, aby kompilator zaaranżował jawne ładowanie biblioteki DLL. Możesz zrobić to samo ręcznie korzystając z LoadLibrary i GetProcAddress.

  1. Zadzwoń pod LoadLibrary, aby załadować bibliotekę DLL. Podaj pełną ścieżkę do biblioteki DLL lub po prostu jej nazwę. W tym drugim przypadku polegasz na poleceniu wyszukiwania DLL, aby zlokalizować bibliotekę DLL. Połączenie z LoadLibrary daje uchwyt modułu.
  2. Zadzwoń pod GetProcAddress, aby uzyskać adres wskazanego wskaźnika funkcji. Musisz dostarczyć uchwyt modułu od kroku 1.
  3. Wywołanie wskaźnika funkcji zwróciło się z kroku 2.
  4. Gdy nie trzeba już wywoływać funkcji, należy użyć FreeLibrary, aby usunąć bibliotekę DLL.

Na każdym kroku należy sprawdzić zwracane wartości funkcji w przypadku błędu. Sposób obsługi błędów jest udokumentowany dla każdej funkcji Win32 API w dokumentacji MSDN (w związku z powyższym). Na przykład, jeśli nie można znaleźć biblioteki DLL, wówczas LoadLibrary zwraca 0. Musisz to wykryć i odpowiednio poradzić sobie z konsekwencjami.

Dyskusja

Chociaż dyrektywa delayed jest bardzo wygodne, ja osobiście nigdy nie używane. Z mojego doświadczenia wynika, że ​​ilekroć musiałem się wyraźnie połączyć, zawsze stwierdziłem, że potrzebuję dodatkowej elastyczności, której nie oferuje delayed. Być może moje potrzeby są szczególne, ale nie zdziw się, jeśli znajdziesz się w kierunku wyraźnych połączeń z numerami LoadLibrary i GetProcAddress.

Jako przykład, właśnie dzisiaj znalazłem się za pomocą LoadLibraryEx, ponieważ chciałem przekazać flagę LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR. Tego rodzaju drobnoziarnista kontrola nie jest dostępna, gdy używasz delayed.

+0

Należy również wspomnieć, że dyrektywa "opóźniona" została wprowadzona w jednej z "późniejszych" wersji Delphi. Nie jest dostępny do Delphi 2007 (nie wiem dokładnie kiedy został wprowadzony). – dummzeuch

+0

@dummzeuch It's 2010 według Rob. Naprawdę nie uważam, żeby rok 2010 był "jedną z późniejszych wersji Delphi" osobiście! –

+0

To dlatego wstawiam "później" w cudzysłowie. – dummzeuch

Powiązane problemy