2009-06-25 20 views
6

Jestem zajęty kodowaniu biblioteki dll, która dostarcza kilka funkcji do aplikacji hosta. Ta aplikacja wywołuje dynamicznie bibliotekę dll, ładując i zwalniając ją po każdym wywołaniu funkcji.Delphi Dynamic Dll - zmienna globalna

Nie mam kontroli nad aplikacją hosta. Mogę pracować tylko z wewnątrz biblioteki DLL. Czy istnieje sposób, w jaki mogę przechowywać pewne zmienne w pamięci, aby móc je ponownie wykorzystać w ramach każdej funkcji? Oczywiście globalny zmienny zostanie wyczyszczony, gdy biblioteka DLL zostanie rozładowana przez aplikację hosta. Zapisywanie dll do plików brzmi bardzo brudny!

Czy ktoś może zaproponować sposób przypisania zmiennej, którą mogę zachować na poziomie globalnym?

Dzięki

+3

Twój projekt jest zły z wielu powodów. Czy zastanawiałeś się nad możliwością wielu wystąpień aplikacji hosta (szybkie przełączanie użytkowników, używając pod Terminal Server) lub aplikacji hosta wywołującej funkcje DLL z wielu wątków? Staraj się unikać globalnego/wspólnego stanu za wszelką cenę. – mghie

Odpowiedz

4

Myślę, że masz tu dwie główne opcje.

  1. oferta 2 wersje swojej funkcji, to masz teraz, plus inny gdzie przechodzą one w buforze (rekord, cokolwiek), które można odczytać z poprzedniego stanu i oczywiście aktualizacji stanu na. Nazwij to wysoką perfekcyjną wersją funkcji. Będą chcieli z niego skorzystać.

  2. Zapisz stan tak, jakbyś plik cookie (to w zasadzie to, co to jest) w pliku gdzieś.

Wariant 1 wymaga modyfikacji aplikacji gospodarza, ale byłoby atrakcyjne dla twórcy aplikacji gospodarza wykorzystać opcja 2 nie wymagają zmian w aplikacji gospodarza, ale nie będzie tak wydajnych.

Nie byłbym osobiście skłonny do zaczynania się z liczeniem referencji, prawdopodobnie aplikacja hosta jest rozładowywana z jakiegoś powodu, gdybym był deweloperem aplikacji hosta, co by mnie zdenerwowało.

+0

dzięki - myślę, że to jest najlepszy zakład. Wolałbym zapisać do pliku i wykonać trafienie wydajności niż ryzyka niż błądzenie z odniesień dll. Być może twórcy aplikacji hosta zdecydują się na wersję o wysokiej wydajności, która będzie się rozwijać – Crudler

1

Najlepszym sposobem jest użycie klasy zawierającej "globals". Inicjujesz obiekt i podajesz go jako parametr dla funkcji dll. Ale to ci nie pomoże, ponieważ nie możesz zmienić aplikacji wywołującej.

Jeśli zachodzi potrzeba przechowywania danych globalnych w bibliotece dll, rozwiązaniem jest zapisanie ich w pliku. Ma to jednak poważny wpływ na wydajność.

0

Gdybym był tobą, zapisałbym wartości tych globalnych zmiennych w pliku, gdy dll zostanie zwolniony i załaduje je, gdy zostanie zainicjowany. Tak więc nie ma powodu, aby zapisać zrzut pamięci biblioteki DLL na dysku.

4

Ostrzeżenie, brudne Hack:

Można załadować samemu.

Każde połączenie z LoadLibrary zwiększa licznik referencji, FreeLibrary zmniejsza go. Tylko jeśli licznik osiągnie zero, biblioteka DLL jest rozładowywana.

Jeśli po raz pierwszy plik DLL zostanie załadowany, wystarczy ponownie załadować bibliotekę, zwiększając licznik odwołań. Jeśli aplikacja wywołująca wywoła FreeLibrary licznik odwołań zostanie zmniejszona, ale biblioteka DLL nie zostanie rozładowana.

EDIT: W mghi wskazał, DLL zostaną rozładowane, gdy proces kończy się, czy liczba referencyjna wynosi zero lub nie.

+1

Tak, ale z drugiej strony ta metoda dodaje wiele bałaganu, kiedy należy zdecydować, kiedy dll ma się naprawdę rozładować, ponieważ nie będzie musiał działać cały czas. Następnie dll powinien sprawdzić, czy aplikacja hosta nadal istnieje okresowo, co mi się nie podoba, ale to tylko ja. – zz1433

+3

@Aldo: Not true - jeśli tylko jeden proces korzysta z biblioteki DLL, zostanie on usunięty po zakończeniu procesu, niezależnie od tego, czy liczba odwołań osiągnęła 0, czy nie. – mghie

2

Innym rozwiązaniem, jeśli masz dużą ilość danych globalnych do udostępnienia, byłoby utworzenie usługi Windows do "buforowania" danych stanu. Trzeba również zaimplementować pewien rodzaj IPC, który działa na granicy procesu, takich jak pliki mapowane w pamięci, skrzynki pocztowe, COM (pojedyncze wystąpienie w tym przypadku), TCP/IP ect. Może się okazać, że to obciążenie będzie czymś więcej niż tylko zapisaniem stanu do pliku, dlatego zaleciłbym takie podejście tylko wtedy, gdy ilość danych stanu jest nadmierna lub będą one rozpatrywane tylko w częściach całości dla każdego żądania do twojej biblioteki DLL.

W przypadku podejścia COM usługa nie musi wykonywać innych czynności niż żądanie (i przytrzymanie) instancji obiektu COM, której będzie używać do utrzymywania stanu. Ponieważ jest to obiekt COM pojedynczej instancji, wszystkie żądania będą dotyczyły tej samej instancji, co umożliwi zapisanie stanu między żądaniami. Żądania do obiektu są szeregowane, więc może to być problem z wydajnością, jeśli wielu klientów żąda danych na tym samym komputerze w tym samym czasie.

+1

Aby rozwinąć ten pomysł, możesz sprawić, że DLL będzie bardzo cienką warstwą, która przekieruje połączenie do usługi. Mięso pracy może być wykonane w serwisie i może utrzymać stan. Dodatkową zaletą tego byłoby zmniejszenie rozmiaru biblioteki DLL i przyspieszenie czasu ładowania biblioteki DLL (co można powiedzieć, że aplikacja wykonuje każde wywołanie funkcji). – Kieveli

+0

@Kieveli - Dobra uwaga, ale wciąż trzeba ustanowić jakiś rodzaj IPC. Com (pojedyncza instancja) byłby prostym rozwiązaniem, w takim przypadku usługa może nadal nic nie robić, tylko żądać i wstrzymywać odwołanie do utrzymywania obiektu. – skamradt

+0

ten prawdopodobnie będzie najbardziej zabawny! Ale myślę, że po prostu przykleję się do pliku, tak jak mówisz, obciążenie prawdopodobnie będzie większe, a jest więcej ris, jeśli chodzi o coś, co można zmienić wrond. Dzięki, tho – Crudler

0

Zapisz wartości w Rejestrze, gdy biblioteka DLL zostanie zwolniona, i odczytaj wartości z Rejestru po załadowaniu biblioteki DLL. Nie zapomnij podać wartości domyślnej, gdy odczyt odkryje, że klucz nie został ustawiony.

-Al.

0

Zgadzam się z poprzednimi komentarzami na temat globalnych informacji państwowych, które są niebezpieczne, chociaż mogę sobie wyobrazić, że mogą być potrzebne.

proponuję czystsze wersji brudnej siekać DR, że nie ma wadę, że są trwałe jak skamradt za odpowiedź:

Bardzo mały app:

ona ma wygląd w ogóle, utrzymuje się od wyświetlane na pasku zadań.

Zadanie nr 1: Załaduj DLL

Zadanie nr 2: Weź To wiersz polecenia, uruchom go i czekać na to, aby zakończyć.

Zadanie nr 3: Unload DLL

Zadanie nr 4: Zakończ.

Instalator:

Okazuje skrót (y) do głównej aplikacji i modyfikuje je tak małe przebiegi aplikacji, oryginalna lokalizacja skrót wskazał staje się pierwszy parametr.

Wyniki: DLL pozostaje w pamięci tylko tak długo, jak główna aplikacja jest uruchomiona, ale nie jest rozładowywana za każdym razem, gdy program ją zrzuca.

0

ten może być również pomocne

option 1: Utwórz udostępniony obszar pamięci, który przechowuje twoje zmienne poparte pliku stronicowania - jeśli jesteś w stanie otworzyć ten wspólny obszar pamięci, twój dll został uprzednio załadowany (zakładając, że „prywatne "nazwa pamięci współużytkowanej, może nazywać się coś w rodzaju process_id_yourdllname) - jeśli nie możesz go otworzyć, to po raz pierwszy ją utworzysz i zainicjujesz. Jeśli ją utworzysz, nie będziesz już jej kasował - ale jeśli ją otworzysz, zamkniesz ją - podczas rozładowywania. Wierzę, że obszar ten zostanie zwolniony po zamknięciu aplikacji, ponieważ żadne inne aplikacje nie powinny obsługiwać tego konkretnego "prywatnego" obszaru pamięci współużytkowanej.

option 2: Utwórz sekundę.dll, który istnieje tylko w celu zarządzania zmiennymi globalnymi. Twoja biblioteka dll A może załadować dll B, a nie zwolnić, umieszczając w bibliotece DLL wszystko, co potrzebujesz, aby zarządzać zmiennymi globalnymi. Powinno zniknąć, gdy aplikacja zniknie, i nie sądzę, że prawdopodobnie będziesz musiał dbać o (prawdopodobnie nieprzydatne) liczenie referencyjne (ponieważ nie wyładowałbyś biblioteki DLL B).