Autor Wątek: DLLMain() - konieczne ?  (Przeczytany 2969 razy)

Offline Ed

  • Użytkownik

# Luty 18, 2007, 02:57:04
Witam

Chciałbym się dowiedziec do czego potrzbne jest DLLMain() ? Czy jest to funckja konieczna w kodzie ? Jak narazie jej nie posiadam w projekcie dll ale przeczytałem że powinna sie znajdować . Do czego konkrenie służy ?

Offline Mr. Spam

  • Miłośnik przetworów mięsnych

Offline Krzysiek K.

  • Redaktor
    • DevKK.net

# Luty 18, 2007, 04:29:00
Witam

Chciałbym się dowiedziec do czego potrzbne jest DLLMain() ? Czy jest to funckja konieczna w kodzie ? Jak narazie jej nie posiadam w projekcie dll ale przeczytałem że powinna sie znajdować . Do czego konkrenie służy ?
Przez DLLMain system Windows powiadamia DLL'kę o tym, co się z nią dzieje. O ile dobrze pamiętam, możliwe są cztery typy zdarzeń:
- biblioteka została załadowana do pamięci,
- uruchomiono nowy program korzystający z biblioteki,
- zamknięto program korzystający z biblioteki,
- biblioteka zostanie za chwilę usunięta z pamięci

Offline Xion

  • Redaktor
    • xion.log

# Luty 18, 2007, 10:57:32
DLLMain (zwana też DllEntryPoint) nie jest konieczna, jeżeli nie musisz przeprowadzać żadnych czynności inicjalizacyjnych lub sprzątających. To już oczywiście zależy od jego, jakie funkcje posiada twoja biblioteka; jeżeli np. obsługuje ona sieć poprzez WinSock, to oczywiście potrzebne są wywołania WSAStartup i WSAShutDown, które należy umieścić właśnie w DllMain.

Offline Ed

  • Użytkownik

# Luty 18, 2007, 14:52:01
Chciałbym się jeszcze dowiedzieć  bo obiło mi się  o uszy , czy to prawda ze DllMain jest potrzebne gdy moja aplikacja alokuje pamięć korzystając (np wykorzystuje funkcje DLLki do alokacji pamięci) z mojej DLL (np klasa dla buforka)

Offline Złośliwiec

  • Użytkownik
    • Dark Cult

# Luty 18, 2007, 15:05:08
Chciałbym się jeszcze dowiedzieć  bo obiło mi się  o uszy , czy to prawda ze DllMain jest potrzebne gdy moja aplikacja alokuje pamięć korzystając (np wykorzystuje funkcje DLLki do alokacji pamięci) z mojej DLL (np klasa dla buforka)

No chyba, bo inaczej jak by się DLL miał dowiedzieć, kiedy zwolnić tę pamięć? Oczywiście zakładając, że DLL nie nakłada na aplikację obowiązku zwalniania pamięci, co jest dość prymitywnym rozwiązaniem :).

Offline Krzysiek K.

  • Redaktor
    • DevKK.net

# Luty 18, 2007, 15:14:26
No chyba, bo inaczej jak by się DLL miał dowiedzieć, kiedy zwolnić tę pamięć?
W tym miejscu dołożę się z własnym pytaniem: kiedy są odpalane konstruktory i destruktory obiektów globalnych DLL'ki? Strzelałbym, że jest jakiś _DLLMainCrtStartup, ale czy ktoś wie dokładnie? :)


Oczywiście zakładając, że DLL nie nakłada na aplikację obowiązku zwalniania pamięci, co jest dość prymitywnym rozwiązaniem :).
To nawet by nie przeszło, bo zwalnianie pamięci przydzielonej w DLL w jakim kolwiek innym miejscu najprawdopodobniej doprowadzi do wywalenia się czegoś. Powód jest prosty: runtime zazwyczaj optymalizuje przydzielanie pamięci (np. przydziela z zapasem, żeby rzadziej odwoływać się do API Windowsa), wobec czego tylko runtime danej aplikacji "wie", co trzeba zrobić żeby pamięć zwolnić.

Offline duzamasa

  • Użytkownik

# Luty 18, 2007, 18:16:02
Cytat: Krzysiek K.
Strzelałbym, że jest jakiś _DLLMainCrtStartup, ale czy ktoś wie dokładnie
Tak, jest. A dokladnie: _DllMainCRTStartup. Obiekty sa inicjowane w powiadomieniu DLL_PROCESS_ATTACH przed wywolaniem funkcji DllMain (jesli w ogole jest).

st3tc

  • Gość
# Luty 18, 2007, 18:21:48
Chciałbym się dowiedziec do czego potrzbne jest DLLMain() ? Czy jest to funckja konieczna w kodzie ?
To prosty callback. Nie jest potrzebny. Jeżeli nie jesteś pewny czy go potrzebujesz - to oznacza, że go nie potrzebujesz :).

jeżeli np. obsługuje ona sieć poprzez WinSock, to oczywiście potrzebne są wywołania WSAStartup i WSAShutDown, które należy umieścić właśnie w DllMain.
Nie. Jedynymi operacjami dozwolonymi w DllMain są operację "na własnym podwórku" oraz wszystkie takie które nie powodują ładowania innych dll-ek, oraz wywołania z Kernelka, który to jest gwarantowany jako istniejący :).

Cytat: MSDN Library
The entry-point function should perform only simple initialization or termination tasks. It must not call the LoadLibrary or LoadLibraryEx function (or a function that calls these functions), because this may create dependency loops in the DLL load order. This can result in a DLL being used before the system has executed its initialization code. Similarly, the entry-point function must not call the FreeLibrary function (or a function that calls FreeLibrary) during process termination, because this can result in a DLL being used after the system has executed its termination code.

Because Kernel32.dll is guaranteed to be loaded in the process address space when the entry-point function is called, calling functions in Kernel32.dll does not result in the DLL being used before its initialization code has been executed. Therefore, the entry-point function can call functions in Kernel32.dll that do not load other DLLs. For example, DllMain can create synchronization objects such as critical sections and mutexes, and use TLS.

Calling functions that require DLLs other than Kernel32.dll may result in problems that are difficult to diagnose. For example, calling User, Shell, and COM functions can cause access violation errors, because some functions load other system components. Conversely, calling functions such as these during termination can cause access violation errors because the corresponding component may already have been unloaded or uninitialized.

Chciałbym się jeszcze dowiedzieć  bo obiło mi się  o uszy , czy to prawda ze DllMain jest potrzebne gdy moja aplikacja alokuje pamięć korzystając (np wykorzystuje funkcje DLLki do alokacji pamięci) z mojej DLL (np klasa dla buforka)
Jeżeli alokacji dokonuje Twoja dll-ka, to dealokacja musi przebiegać w niej samej. ALE: Jeżeli aplikacja alokuje coś za pośrednictwem dll-ki, to aplikacja powinna być (imho) zobowiązana do dealokacji (posprzątania po sobie).

No chyba, bo inaczej jak by się DLL miał dowiedzieć, kiedy zwolnić tę pamięć? Oczywiście zakładając, że DLL nie nakłada na aplikację obowiązku zwalniania pamięci, co jest dość prymitywnym rozwiązaniem
Moim zdaniem nie nakładanie takiego obowiązku jest błędem :). Alokuję coś – mam obowiązek posprzątać :)

W tym miejscu dołożę się z własnym pytaniem: kiedy są odpalane konstruktory i destruktory obiektów globalnych DLL'ki? Strzelałbym, że jest jakiś _DLLMainCrtStartup, ale czy ktoś wie dokładnie? :)
To opisuje standard C++, pozostawiając detale implementacji. Dla VC++ : 
Kompilator buduje tablicę z adresami funkcji które wywołują konstruktor obiektu statycznego oraz rejestrują poprzez atexit() (ISO) funkcję wywołującą destruktor . Zgodnie z standardem te funkcje mają być wywołana po zakończeniu main poprzez funkcję exit(). Poniewać DLL do ext MS-a ;) i nie ma exit - są wywoływane z  _DllMainCRTStartup po zakończeniu DllMain. W przypadku MS-a, tablica funkcji startowych jest wywoływana poprzez runtimowe "initterm()". Destrukcja jest w odwrotnej kolejności (LIFO).

Oczywiście zakładając, że DLL nie nakłada na aplikację obowiązku zwalniania pamięci, co jest dość prymitywnym rozwiązaniem :).
To nawet by nie przeszło, bo zwalnianie pamięci przydzielonej w DLL w jakim kolwiek innym miejscu najprawdopodobniej doprowadzi do wywalenia się czegoś. Powód jest prosty: runtime zazwyczaj optymalizuje przydzielanie pamięci (np. przydziela z zapasem, żeby rzadziej odwoływać się do API Windowsa), wobec czego tylko runtime danej aplikacji "wie", co trzeba zrobić żeby pamięć zwolnić.
To o czym mówisz ma "podstawy prawne" w Windows :). Nie jest legalne zwalnianie pamięci z innego heapka niż własny – zakończy się to faultem aplikacji.
Są w sumie dwa prawidłowe wyjścia:
1.   Dll-ka musi zagwarantować możliwość dealokacji – np. metody "Release"
2.   Najlepsza: używać DLL runtimów kompilatora. Alokacja/dealokacja jest scentralizowana w ramach procesu (msvcrXX.dll w MS). Wciąż mamy możliwość tworzenia własnych managerów pamięci.

Ad 1. Jedyny sens takiego rozwiązania to gdy tworzymy DLL, która musi nie może być zależna od konkretnej wersji CRT (np uniwersalna biblioteka). Można ją wtedy zlinkować statycznie do CRT.

Podsumowując - jest naprawdę minimalna ilość powodów kiedy należy użyć DllMain :)
« Ostatnia zmiana: Luty 18, 2007, 18:33:09 wysłana przez st3tc »

Offline lgromanowski

  • Użytkownik
    • OpenMW, Elderscrolls III: Morrowind engine reimplementation

# Luty 19, 2007, 13:31:43
Cześć,
zerknij na:
http://www.microsoft.com/whdc/driver/kernel/DLL_bestprac.mspx (link bezpośredni: DLL_bestprac.doc)
w sumie to znajdują się tam rzeczy, które podali Tobie przedpiścy + kilka innych ciekawostek.