#ifdef CRTDLL /*** *crtdll.c - CRT initialization for a DLL using the CRTDLL model of C run-time * * Copyright (c) 1991-1994, Microsoft Corporation. All rights reserved. * *Purpose: * This module contains the initialization entry point for the C run-time * stub in this DLL. All C run-time code is located in the C Run-Time * Library DLL "CRTDLL.DLL", except for a little bit of start-up code in * the EXE, and this code in each DLL. This code is necessary to invoke * the C++ constructors for the C++ code in this DLL. * * This entry point should either be specified as the DLL initialization * entry point, or else it must be called by the DLL initialization entry * point of the DLL with the same arguments that the entry point receives. * *Revision History: * 05-19-92 SKS Initial version * 08-01-92 SRW winxcpt.h replaced bu excpt.h which is included by oscalls.h * 09-16-92 SKS Prepare for C8 C++ for MIPS by calling C++ constructors * 09-29-92 SKS _CRT_DLL must be a WINAPI function! * 05-11-93 SKS Add _DllMainCRTStartup as an alternative to _CRT_INIT * 06-05-93 SRW Pin CRTDLL.DLL in memory once loaded. * 06-07-93 GJF Added __proc_attached flag. * 06-07-93 GJF Backed out SteveWo's change of 06-05 and put it into * crtlib.c * 06-08-93 SKS Clean up failure handling in _CRT_INIT * 07-16-93 SRW ALPHA Merge * 12-02-93 SKS Add atexit/_onexit support. These routines must be * defined here so that DLL's that are linked with * CRTDLL.LIB will get these versions (suitable for DLLs), * not the versions of atexit/_onexit from CRTDLL.DLL, * which are only suitable for an EXE file. * 07-18-94 GJF Moved over Win32s support from VC 2.0 tree. * *******************************************************************************/ /* * SPECIAL BUILD MACRO! Note that crtexe.c (and crtexew.c) is linked in with * the client's code. It does not go into crtdll.dll! Therefore, it must be * built under the _DLL switch (like user code) and CRTDLL must be undefined. */ #undef CRTDLL #define _DLL #include #include #include #include #define _DECL_DLLMAIN /* enable prototypes for DllMain and _CRT_INIT */ #include /* * routine in DLL to do initialization (in this case, C++ constructors) */ typedef void (_CALLTYPE1 *PF)(void); extern void _CALLTYPE4 _initterm(PF *, PF *); /* * pointers to initialization sections */ extern PF __xc_a[], __xc_z[]; /* C++ initializers */ /* * Flag identifying the host as Win32s or not-Win32s. */ int __win32sflag = 0; static int onexitflag = 0; /* * flag set iff _CRTDLL_INIT was called with DLL_PROCESS_ATTACH */ static int __proc_attached = 0; /* * Pointers to beginning and end of the table of function pointers manipulated * by _onexit()/atexit(). The atexit/_onexit code is shared for both EXE's and * DLL's but different behavior is required. These values are initialized to * 0 by default and will be set to point to a malloc-ed memory block to mark * this module as an DLL. */ PF *__onexitbegin; PF *__onexitend; /* * User routine DllMain is called on all notifications */ extern BOOL WINAPI DllMain( HANDLE hDllHandle, DWORD dwReason, LPVOID lpreserved ) ; /*** *BOOL WINAPI _CRT_INIT(hDllHandle, dwReason, lpreserved) - C++ DLL initialization. * *Purpose: * This routine does the C runtime initialization for a DLL using CRTDLL. * It may be specified as the entry point for the DLL, or it may be * called by the routine that is the DLL entry point. * * On DLL_PROCESS_ATTACH, the C++ constructors for the DLL will be called. * * On DLL_PROCESS_DETACH, the C++ destructors and _onexit/atexit routines * will be called. * *Entry: * *Exit: * *******************************************************************************/ BOOL WINAPI _CRT_INIT( HANDLE hDllHandle, DWORD dwReason, LPVOID lpreserved ) { unsigned osver; /* * First, set the __proc_attached flag */ if ( dwReason == DLL_PROCESS_ATTACH ) __proc_attached++; else if ( dwReason == DLL_PROCESS_DETACH ) { if ( __proc_attached > 0 ) __proc_attached--; else /* * no prior process attach. just return failure. */ return FALSE; } /* * Get the host version (on first call). */ if ( __win32sflag == 0 ) { osver = GetVersion(); if ( ((osver & 0x00ff) == 3) && ((osver >> 31) & 1) ) __win32sflag++; else __win32sflag--; } /* * do C++ constructors (initializers) specific to this DLL */ if ( dwReason == DLL_PROCESS_ATTACH ) { /* * If the host is Win32s, create the onexit table and do C++ * constructors only for the first connecting process. */ if ( (__win32sflag < 0) || (__proc_attached == 1) ) { if ( __win32sflag < 0 ) { /* * not Win32s! just malloc the table. */ if ( (__onexitbegin = (PF *)malloc(32 * sizeof(PF))) == NULL ) /* * cannot allocate minimal required * size. generate failure to load DLL */ return FALSE; } else if ( __proc_attached == 1 ) { if ( (__onexitbegin = (PF *)GlobalAlloc( GMEM_FIXED | GMEM_SHARE, 32 * sizeof(PF) )) == NULL ) /* * cannot allocate minimal required * size. generate failure to load DLL */ return FALSE; } *(__onexitbegin) = (PF) NULL; __onexitend = __onexitbegin; /* * Invoke C++ constructors */ _initterm(__xc_a,__xc_z); } } else if ( dwReason == DLL_PROCESS_DETACH ) { if ( (__win32sflag < 0) || (__proc_attached == 0) ) { /* * Any basic clean-up code that goes here must be * duplicated below in _DllMainCRTStartup for the * case where the user's DllMain() routine fails on a * Process Attach notification. This does not include * calling user C++ destructors, etc. */ /* * do _onexit/atexit() terminators * (if there are any) * * These terminators MUST be executed in * reverse order (LIFO)! * * NOTE: * This code assumes that __onexitbegin * points to the first valid onexit() * entry and that __onexitend points * past the last valid entry. If * __onexitbegin == __onexitend, the * table is empty and there are no * routines to call. */ if (__onexitbegin) { PF * pfend = __onexitend; while ( -- pfend >= __onexitbegin ) /* * if current table entry is not * NULL, call thru it. */ if ( *pfend != NULL ) (**pfend)(); /* * just in case Win32s doesn't clean up after * us (any bets?), free the block holding * onexit table */ if ( __win32sflag > 0 ) GlobalFree( (HGLOBAL)__onexitbegin ); else free(__onexitbegin); } } } return TRUE; } /*** *BOOL WINAPI _DllMainCRTStartup(hDllHandle, dwReason, lpreserved) - C++ DLL initialization. * *Purpose: * This is an alternative entry point for DLL's linked with the C run-time * libs, rather than using _CRT_INIT. The user should specify this routine * as the DLL entry point, and define his/her own routine DllMain to get * notifications in his/her code. CRT initialization/termination will be * done before or after calling DllMain, as appropriate. * *Entry: * *Exit: * *******************************************************************************/ BOOL WINAPI _DllMainCRTStartup( HANDLE hDllHandle, DWORD dwReason, LPVOID lpreserved ) { BOOL retcode = TRUE; /* * If this is a process detach notification, check that there has * been a prior process attach notification. */ if ( (dwReason == DLL_PROCESS_DETACH) && (__proc_attached == 0) ) return FALSE; if ( dwReason == DLL_PROCESS_ATTACH || dwReason == DLL_THREAD_ATTACH ) retcode = _CRT_INIT(hDllHandle, dwReason, lpreserved); if ( retcode ) retcode = DllMain(hDllHandle, dwReason, lpreserved); /* * If _CRT_INIT successfully handles a Process Attach notification * but the user's DllMain routine returns failure, we need to do * clean-up of the C run-time similar to what _CRT_INIT does on a * Process Detach Notification. */ if ( dwReason == DLL_PROCESS_DETACH || dwReason == DLL_THREAD_DETACH ) { if ( _CRT_INIT(hDllHandle, dwReason, lpreserved) == FALSE ) retcode = FALSE ; } return retcode ; } /*** *_onexit, atexit - calls to DLL versioons of _onexit & atexit in CRTDLL.DLL * *Purpose: * A DLL linked with CRTDLL.LIB must not call the standard _onexit or * atexit exported from CRTDLL.DLL, but an EXE linked with CRTDLL.LIB * will call the standard versions of those two routines. Since the * names are exported from CRTDLL.DLL, we must define them here for DLLs. * All DLLs linked with CRTDLL.LIB must pull in this startup object. * *Entry: * Same as the regular versions of _onexit, atexit. * *Exit: * Same as the regular versions of _onexit, atexit. * *Exceptions: * *******************************************************************************/ extern _onexit_t _CALLTYPE1 __dllonexit(_onexit_t, PF **, PF **); _onexit_t _CALLTYPE1 _onexit ( _onexit_t func ) { unsigned osver; _onexit_t retval; /* * Get the host version (on first call). */ if ( __win32sflag == 0 ) { osver = GetVersion(); if ( ((osver & 0x00ff) == 3) && ((osver >> 31) & 1) ) __win32sflag++; else __win32sflag--; } /* * If we are running in Win32s, test and set the flag used to * serialize access. Note that we assume no process switch can take * place between a successful test of the flag and the setting of * the flag. */ if ( __win32sflag > 0 ) { while ( onexitflag > 0 ) Sleep(0); onexitflag++; } retval = __dllonexit(func, &__onexitbegin, &__onexitend); if ( __win32sflag > 0 ) onexitflag--; return retval; } int _CALLTYPE1 atexit ( PF func ) { return (_onexit((_onexit_t)func) == NULL) ? -1 : 0; } #endif /* CRTDLL */