Notatka
Dostęp do tej strony wymaga autoryzacji. Może spróbować zalogować się lub zmienić katalogi.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
Opcjonalny punkt wejścia do biblioteki linków dynamicznych (DLL). Po uruchomieniu lub zakończeniu procesu lub wątku system wywołuje funkcję punktu wejścia dla każdej załadowanej biblioteki DLL przy użyciu pierwszego wątku procesu. System wywołuje również funkcję punktu wejścia dla biblioteki DLL, gdy jest ładowana lub zwalniana przy użyciu funkcji LoadLibrary i FreeLibrary .
Warning
W punkcie wejścia biblioteki DLL istnieją istotne ograniczenia dotyczące tego, co można bezpiecznie zrobić. Zobacz Ogólne najlepsze rozwiązania dotyczące określonych interfejsów API Windows, które są niebezpieczne do wywołania w dllMain. Jeśli potrzebujesz niczego, ale najprostszego inicjowania, wykonaj to w funkcji inicjowania dla biblioteki DLL. Aplikacje mogą wymagać wywołania funkcji inicjowania po uruchomieniu biblioteki DllMain i przed wywołaniem innych funkcji w bibliotece DLL.
Przykład
BOOL WINAPI DllMain(
HINSTANCE hinstDLL, // handle to DLL module
DWORD fdwReason, // reason for calling function
LPVOID lpvReserved ) // reserved
{
// Perform actions based on the reason for calling.
switch( fdwReason )
{
case DLL_PROCESS_ATTACH:
// Initialize once for each new process.
// Return FALSE to fail DLL load.
break;
case DLL_THREAD_ATTACH:
// Do thread-specific initialization.
break;
case DLL_THREAD_DETACH:
// Do thread-specific cleanup.
break;
case DLL_PROCESS_DETACH:
if (lpvReserved != nullptr)
{
break; // do not do cleanup if process termination scenario
}
// Perform any necessary cleanup.
break;
}
return TRUE; // Successful DLL_PROCESS_ATTACH.
}
Jest to przykład funkcji Dynamic-Link Library Entry-Point.
Syntax
BOOL WINAPI DllMain(
_In_ HINSTANCE hinstDLL,
_In_ DWORD fdwReason,
_In_ LPVOID lpvReserved
);
Parameters
-
hinstDLL [in]
-
Dojście do modułu DLL. Wartość jest podstawowym adresem biblioteki DLL. HINSTANCE biblioteki DLL jest taka sama jak HMODULE biblioteki DLL, więc hinstDLL może służyć w wywołaniach do funkcji, które wymagają uchwytu modułu.
-
fdwReason [in]
-
Kod przyczyny wskazujący, dlaczego wywoływana jest funkcja punktu wejścia biblioteki DLL. Ten parametr może być jedną z następujących wartości.
Value Meaning - DLL_PROCESS_ATTACH
- 1
Biblioteka DLL jest ładowana do wirtualnej przestrzeni adresowej bieżącego procesu w wyniku uruchomienia procesu lub w wyniku wywołania metody LoadLibrary. Biblioteki DLL mogą korzystać z tej możliwości, aby zainicjować dowolne dane wystąpienia lub użyć funkcji TlsAlloc do przydzielenia indeksu magazynu lokalnego wątku (TLS).
LpvReserved parametr wskazuje, czy biblioteka DLL jest ładowana statycznie, czy dynamicznie.- DLL_PROCESS_DETACH
- 0
Biblioteka DLL jest zwalniana z wirtualnej przestrzeni adresowej procesu wywołującego, ponieważ została załadowana bezskutecznie lub liczba odwołań osiągnęła zero (procesy zostały zakończone lub wywołane FreeLibrary jeden raz za każdym razem o nazwie LoadLibrary).
LpvReserved parametr wskazuje, czy biblioteka DLL jest zwalniana w wyniku wywołania FreeLibrary, niepowodzenia ładowania lub zakończenia procesu.
Biblioteka DLL może użyć tej możliwości, aby wywołać funkcję TlsFree , aby zwolnić wszystkie indeksy TLS przydzielone przy użyciu protokołu TlsAlloc i zwolnić wszystkie dane lokalne wątku.
Należy pamiętać, że wątek odbierający powiadomienie o DLL_PROCESS_DETACH niekoniecznie jest tym samym wątkiem, który otrzymał powiadomienie DLL_PROCESS_ATTACH .- DLL_THREAD_ATTACH
- 2
Bieżący proces tworzy nowy wątek. W takim przypadku system wywołuje funkcję punktu wejścia wszystkich bibliotek DLL aktualnie dołączonych do procesu. Wywołanie jest wykonywane w kontekście nowego wątku. Biblioteki DLL mogą korzystać z tej możliwości, aby zainicjować miejsce protokołu TLS dla wątku. Wątek wywołujący funkcję punktu wejścia biblioteki DLL z DLL_PROCESS_ATTACH nie wywołuje funkcji punktu wejścia biblioteki DLL z DLL_THREAD_ATTACH.
Należy pamiętać, że funkcja punktu wejścia biblioteki DLL jest wywoływana z tą wartością tylko przez wątki utworzone po załadowaniu biblioteki DLL przez proces. Gdy biblioteka DLL jest ładowana przy użyciu biblioteki LoadLibrary, istniejące wątki nie nazywają funkcji punktu wejścia nowo załadowanej biblioteki DLL.- DLL_THREAD_DETACH
- 3
Wątek kończy się czysto. Jeśli biblioteka DLL przechowywała wskaźnik do przydzielonej pamięci w miejscu protokołu TLS, należy użyć tej możliwości, aby zwolnić pamięć. System wywołuje funkcję punktu wejścia wszystkich aktualnie załadowanych bibliotek DLL z tą wartością. Wywołanie jest wykonywane w kontekście wątku zakończenia. -
lpvReserved [in]
-
Jeśli wartość fdwReason jest DLL_PROCESS_ATTACH, wartość lpvReserved ma wartość NULL dla obciążeń dynamicznych i nie ma wartości NULL dla obciążeń statycznych.
Jeśli plik fdwReason jest DLL_PROCESS_DETACH, lpvReserved ma wartość NULL , jeśli wywołano bibliotekę FreeLibrary lub ładowanie biblioteki DLL nie powiodło się i nie ma wartości NULL , jeśli proces kończy się.
Wartość zwracana
Gdy system wywołuje funkcję DllMain z wartością DLL_PROCESS_ATTACH , funkcja zwraca wartość TRUE , jeśli zakończy się powodzeniem lub fałszem , jeśli inicjowanie zakończy się niepowodzeniem. Jeśli zwracana wartość to FALSE , gdy parametr DllMain jest wywoływany, ponieważ proces używa funkcji LoadLibrary , funkcja LoadLibrary zwraca wartość NULL. (System natychmiast wywołuje funkcję punktu wejścia z DLL_PROCESS_DETACH i zwalnia bibliotekę DLL). Jeśli zwracana wartość to FALSE , gdy parametr DllMain jest wywoływany podczas inicjowania procesu, proces kończy się błędem. Aby uzyskać rozszerzone informacje o błędzie, wywołaj metodę GetLastError.
Gdy system wywołuje funkcję DllMain z dowolną wartością inną niż DLL_PROCESS_ATTACH, zwracana wartość jest ignorowana.
Remarks
DllMain jest symbolem zastępczym nazwy funkcji zdefiniowanej przez bibliotekę. Należy określić rzeczywistą nazwę używaną podczas tworzenia biblioteki DLL. Aby uzyskać więcej informacji, zobacz dokumentację zawartą w narzędziach programistycznych.
Podczas początkowego uruchamiania procesu lub po wywołaniu metody LoadLibrary system skanuje listę załadowanych bibliotek DLL dla tego procesu. Dla każdej biblioteki DLL, która nie została jeszcze wywołana z wartością DLL_PROCESS_ATTACH , system wywołuje funkcję punktu wejścia biblioteki DLL. To wywołanie jest wykonywane w kontekście wątku, który spowodował zmianę przestrzeni adresowej procesu, na przykład podstawowy wątek procesu lub wątek o nazwie LoadLibrary. Dostęp do punktu wejścia jest serializowany przez system w całym procesie. Wątki w dllMain przechowują blokadę modułu ładującego, aby nie można było dynamicznie ładować ani inicjować żadnych dodatkowych bibliotek DLL.
Jeśli funkcja punktu wejścia biblioteki DLL zwraca wartość FALSE po powiadomieniu DLL_PROCESS_ATTACH , otrzyma powiadomienie DLL_PROCESS_DETACH , a biblioteka DLL zostanie natychmiast zwolniona. Jeśli jednak kod DLL_PROCESS_ATTACH zgłasza wyjątek, funkcja punktu wejścia nie otrzyma powiadomienia DLL_PROCESS_DETACH .
Istnieją przypadki, w których funkcja punktu wejścia jest wywoływana dla wątku przerywającego, nawet jeśli funkcja punktu wejścia nigdy nie została wywołana z DLL_THREAD_ATTACH dla wątku:
- Wątek był wątek początkowy w procesie, więc system nazwał funkcję punktu wejścia wartością DLL_PROCESS_ATTACH .
- Wątek był już uruchomiony, gdy wykonano wywołanie funkcji LoadLibrary , więc system nigdy nie nazwał dla niej funkcji punktu wejścia.
Gdy biblioteka DLL zostanie zwolniona z procesu w wyniku nieudanego załadowania biblioteki DLL, zakończenia procesu lub wywołania metody FreeLibrary, system nie wywołuje funkcji punktu wejścia biblioteki DLL z wartością DLL_THREAD_DETACH dla poszczególnych wątków procesu. Biblioteka DLL jest wysyłana tylko powiadomienie DLL_PROCESS_DETACH . Biblioteki DLL mogą skorzystać z tej okazji, aby wyczyścić wszystkie zasoby dla wszystkich wątków znanych z biblioteki DLL.
W przypadku obsługi DLL_PROCESS_DETACH biblioteka DLL powinna zwolnić zasoby, takie jak pamięć sterta tylko wtedy, gdy biblioteka DLL jest zwalniana dynamicznie (parametr lpvReserved ma wartość NULL). Jeśli proces kończy się (parametr lpvReserved jest inny niż NULL), wszystkie wątki w procesie z wyjątkiem bieżącego wątku zostały już zakończone lub zostały jawnie zakończone przez wywołanie funkcji ExitProcess , co może spowodować pozostawienie niektórych zasobów procesu, takich jak sterty w stanie niespójnym. W takim przypadku biblioteka DLL nie jest bezpieczna, aby wyczyścić zasoby. Zamiast tego biblioteka DLL powinna zezwolić systemowi operacyjnemu na odzyskanie pamięci.
W przypadku zakończenia procesu przez wywołanie metody TerminateProcess lub TerminateJobObject biblioteki DLL tego procesu nie będą otrzymywać powiadomień DLL_PROCESS_DETACH . W przypadku zakończenia wątku przez wywołanie metody TerminateThread biblioteki DLL tego wątku nie będą otrzymywać powiadomień DLL_THREAD_DETACH .
Funkcja punktu wejścia powinna wykonywać tylko proste zadania inicjowania lub kończenia. Nie może wywołać funkcji LoadLibrary lub LoadLibraryEx (lub funkcji wywołującej te funkcje), ponieważ może to spowodować utworzenie pętli zależności w kolejności ładowania bibliotek DLL. Może to spowodować, że biblioteka DLL będzie używana przed wykonaniem przez system kodu inicjowania. Podobnie funkcja punktu wejścia nie może wywoływać funkcji FreeLibrary (lub funkcji, która wywołuje FreeLibrary) podczas kończenia procesu, ponieważ może to spowodować, że biblioteka DLL jest używana po wykonaniu przez system kodu zakończenia.
Ponieważ Kernel32.dll ma gwarancję załadowania w przestrzeni adresowej procesu, gdy wywoływana jest funkcja punktu wejścia, wywoływanie funkcji w Kernel32.dll nie powoduje użycia biblioteki DLL przed wykonaniem kodu inicjowania. W związku z tym funkcja punktu wejścia może wywoływać funkcje w Kernel32.dll, które nie ładują innych bibliotek DLL. Na przykład biblioteka DllMain może tworzyć obiekty synchronizacji , takie jak sekcje krytyczne i elementy muteksowe, oraz używać protokołu TLS. Niestety nie ma kompleksowej listy bezpiecznych funkcji w Kernel32.dll.
Wywoływanie funkcji wymagających bibliotek DLL innych niż Kernel32.dll może powodować problemy, które są trudne do zdiagnozowania. Na przykład wywołanie funkcji User, Shell i COM może powodować błędy naruszenia dostępu, ponieważ niektóre funkcje ładują inne składniki systemowe. Z drugiej strony wywoływanie funkcji takich jak te podczas kończenia może spowodować błędy naruszenia dostępu, ponieważ odpowiedni składnik mógł już zostać zwolniony lub niezainicjowany.
Ponieważ powiadomienia DLL są serializowane, funkcje punktu wejścia nie powinny próbować komunikować się z innymi wątkami ani procesami. W rezultacie mogą wystąpić zakleszczenia.
Aby uzyskać informacje na temat najlepszych rozwiązań dotyczących pisania biblioteki DLL, zobacz Dynamic-link library best practices (Najlepsze rozwiązania dotyczące biblioteki linków dynamicznych).
Jeśli biblioteka DLL jest połączona z biblioteką czasu wykonywania języka C (CRT), punkt wejścia udostępniany przez CRT wywołuje konstruktory i destruktory dla obiektów globalnych i statycznych języka C++. W związku z tym te ograniczenia dotyczące bibliotek DllMain mają zastosowanie również do konstruktorów i destruktorów oraz dowolnego kodu, który jest wywoływany z nich.
Rozważ wywołanie elementu DisableThreadLibraryCalls podczas odbierania DLL_PROCESS_ATTACH, chyba że biblioteka DLL jest połączona ze statyczną biblioteką czasu wykonywania języka C (CRT).
Wymagania
| Requirement | Value |
|---|---|
| Minimalny obsługiwany klient |
Windows XP [tylko aplikacje klasyczne] |
| Minimalny obsługiwany serwer |
Windows Server 2003 [tylko aplikacje klasyczne] |
| Header |
|