Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

342 lines
11 KiB

  1. /***
  2. *crtdll.c - CRT initialization for a DLL using the MSVCRT* model of C run-time
  3. *
  4. * Copyright (c) 1991-2001, Microsoft Corporation. All rights reserved.
  5. *
  6. *Purpose:
  7. * This module contains the initialization entry point for the C run-time
  8. * stub in this DLL. All C run-time code is located in the C Run-Time
  9. * Library DLL "MSVCRT*.DLL", except for a little bit of start-up code in
  10. * the EXE, and this code in each DLL. This code is necessary to invoke
  11. * the C++ constructors for the C++ code in this DLL.
  12. *
  13. * This entry point should either be specified as the DLL initialization
  14. * entry point, or else it must be called by the DLL initialization entry
  15. * point of the DLL with the same arguments that the entry point receives.
  16. *
  17. *Revision History:
  18. * 05-19-92 SKS Initial version
  19. * 08-01-92 SRW winxcpt.h replaced bu excpt.h which is included by oscalls.h
  20. * 09-16-92 SKS Prepare for C8 C++ for MIPS by calling C++ constructors
  21. * 09-29-92 SKS _CRT_DLL must be a WINAPI function!
  22. * 04-06-93 SKS Replace _CRTAPI* with _cdecl
  23. * 04-14-93 SKS _DllMainCRTStartup replaces _CRT_INIT
  24. * 04-20-93 SKS Restore _CRT_INIT, must co-exist with DllMainCRTStartup
  25. * 05-24-93 SKS Add indirect definitions of _onexit/atexit.
  26. * 06-08-93 GJF Added __proc_attached flag.
  27. * 06-08-93 SKS Clean up failure handling in _CRT_INIT
  28. * 10-26-93 GJF Replaced PF with _PVFV (defined in internal.h).
  29. * 05-02-94 GJF Add _wDllMainCRTStartup thunk.
  30. * 05-19-94 GJF For Win32S version, only create the onexit-table and
  31. * do the C++ constructors for the first process that
  32. * attaches. Similarly, only execute the table entries
  33. * when the last process detaches. Also, removed bogus
  34. * incrementing and decrementing of __proc_attached flag
  35. * in _DllMainCRTStartup.
  36. * 05-27-94 GJF Replaced conditional compilation on DLL_FOR_WIN32S
  37. * with a runtime test for Win32s.
  38. * 06-04-94 GJF Fixed test for first process attach in Win32s.
  39. * 06-06-94 GJF Use GlobalAlloc for Win32s.
  40. * 06-08-94 SKS Add functn pointer _pRawDllMain, called around DllMain.
  41. * 07-18-94 GJF Must specify GMEM_SHARE in GlobalAlloc.
  42. * 11-08-94 SKS Free __onexitbegin (under !Win32s) to fix memory leak
  43. * 12-13-94 GJF Made Win32s support conditional on _M_IX86.
  44. * 12-13-94 SKS Import the value of "_adjust_fdiv" from the CRTL DLL
  45. * 12-27-94 CFW Remove unused _wDll support.
  46. * 01-10-95 CFW Debug CRT allocs.
  47. * 02-22-95 JWM Spliced in PMAC code.
  48. * 05-24-95 CFW Return value from DllInit.
  49. * 07-24-95 CFW Change PMac onexit malloc to _malloc_crt.
  50. * 11-15-95 BWT Win32s isn't interesting for NT.
  51. * 05-14-96 GJF Changed how failure during process attach is handled.
  52. * 06-27-96 GJF Purged Win32s support (removed __win32sflag). Replaced
  53. * defined(_WIN32) with !defined(_MAC). Removed NT_BUILD.
  54. * 02-01-99 GJF Slight change to terminator execution loop to allow
  55. * terminators to register more terminators.
  56. * 04-28-99 PML Wrap __declspec(allocate()) in _CRTALLOC macro.
  57. * 05-11-99 KBF Wrap RTC support in #ifdef.
  58. * 05-17-99 PML Remove all Macintosh support.
  59. *
  60. *******************************************************************************/
  61. #ifdef CRTDLL
  62. /*
  63. * SPECIAL BUILD MACRO! Note that crtexe.c (and crtexew.c) is linked in with
  64. * the client's code. It does not go into crtdll.dll! Therefore, it must be
  65. * built under the _DLL switch (like user code) and CRTDLL must be undefined.
  66. */
  67. #undef CRTDLL
  68. #undef _DLL
  69. #define _DLL
  70. #include <cruntime.h>
  71. #include <oscalls.h>
  72. #include <internal.h>
  73. #include <stdlib.h>
  74. #define _DECL_DLLMAIN /* enable prototypes for DllMain and _CRT_INIT */
  75. #include <process.h>
  76. #include <dbgint.h>
  77. #include <rtcapi.h>
  78. #include <sect_attribs.h>
  79. #ifdef _M_IX86
  80. /*
  81. * The local copy of the Pentium FDIV adjustment flag
  82. * and the address of the flag in MSVCRT*.DLL.
  83. */
  84. extern int _adjust_fdiv;
  85. extern int * _imp___adjust_fdiv;
  86. #endif
  87. /*
  88. * routine in DLL to do initialization (in this case, C++ constructors)
  89. */
  90. extern void __cdecl _initterm(_PVFV *, _PVFV *);
  91. /*
  92. * pointers to initialization sections
  93. */
  94. extern _CRTALLOC(".CRT$XCA") _PVFV __xc_a[];
  95. extern _CRTALLOC(".CRT$XCZ") _PVFV __xc_z[]; /* C++ initializers */
  96. /*
  97. * flag set iff _CRTDLL_INIT was called with DLL_PROCESS_ATTACH
  98. */
  99. static int __proc_attached = 0;
  100. /*
  101. * Pointers to beginning and end of the table of function pointers manipulated
  102. * by _onexit()/atexit(). The atexit/_onexit code is shared for both EXE's and
  103. * DLL's but different behavior is required. These values are initialized to
  104. * 0 by default and will be set to point to a malloc-ed memory block to mark
  105. * this module as an DLL.
  106. */
  107. extern _PVFV *__onexitbegin;
  108. extern _PVFV *__onexitend;
  109. /*
  110. * User routine DllMain is called on all notifications
  111. */
  112. extern BOOL WINAPI DllMain(
  113. HANDLE hDllHandle,
  114. DWORD dwReason,
  115. LPVOID lpreserved
  116. ) ;
  117. /* _pRawDllMain MUST be a common variable, not extern nor initialized! */
  118. BOOL (WINAPI *_pRawDllMain)(HANDLE, DWORD, LPVOID);
  119. /***
  120. *BOOL WINAPI _CRT_INIT(hDllHandle, dwReason, lpreserved) - C++ DLL
  121. * initialization.
  122. *BOOL WINAPI _DllMainCRTStartup(hDllHandle, dwReason, lpreserved) - C++ DLL
  123. * initialization.
  124. *
  125. *Purpose:
  126. * This is the entry point for DLL's linked with the C/C++ run-time libs.
  127. * This routine does the C runtime initialization for a DLL linked with
  128. * MSVCRT.LIB (whose C run-time code is thus in MSVCRT*.DLL.)
  129. * It will call the user notification routine DllMain on all 4 types of
  130. * DLL notifications. The return code from this routine is the return
  131. * code from the user notification routine.
  132. *
  133. * On DLL_PROCESS_ATTACH, the C++ constructors for the DLL will be called.
  134. *
  135. * On DLL_PROCESS_DETACH, the C++ destructors and _onexit/atexit routines
  136. * will be called.
  137. *
  138. *Entry:
  139. *
  140. *Exit:
  141. *
  142. *******************************************************************************/
  143. BOOL WINAPI _CRT_INIT(
  144. HANDLE hDllHandle,
  145. DWORD dwReason,
  146. LPVOID lpreserved
  147. )
  148. {
  149. /*
  150. * If this is a process detach notification, check that there has
  151. * been a prior (successful) process attachment.
  152. */
  153. if ( dwReason == DLL_PROCESS_DETACH ) {
  154. if ( __proc_attached > 0 )
  155. __proc_attached--;
  156. else
  157. /*
  158. * no prior process attach. just return failure.
  159. */
  160. return FALSE;
  161. }
  162. #ifdef _M_IX86
  163. /*
  164. * Set the local copy of the Pentium FDIV adjustment flag
  165. */
  166. _adjust_fdiv = * _imp___adjust_fdiv;
  167. #endif
  168. /*
  169. * do C++ constructors (initializers) specific to this DLL
  170. */
  171. if ( dwReason == DLL_PROCESS_ATTACH ) {
  172. /*
  173. * create the onexit table.
  174. */
  175. if ( (__onexitbegin = (_PVFV *)_malloc_crt(32 * sizeof(_PVFV)))
  176. == NULL )
  177. /*
  178. * cannot allocate minimal required
  179. * size. generate failure to load DLL
  180. */
  181. return FALSE;
  182. *(__onexitbegin) = (_PVFV) NULL;
  183. __onexitend = __onexitbegin;
  184. /*
  185. * Run the RTC initialization code for this DLL
  186. */
  187. #ifdef _RTC
  188. _RTC_Initialize();
  189. atexit(_RTC_Terminate);
  190. #endif
  191. /*
  192. * Invoke C++ constructors
  193. */
  194. _initterm(__xc_a,__xc_z);
  195. /*
  196. * Increment the process attached flag.
  197. */
  198. __proc_attached++;
  199. }
  200. else if ( dwReason == DLL_PROCESS_DETACH ) {
  201. /*
  202. * Any basic clean-up code that goes here must be
  203. * duplicated below in _DllMainCRTStartup for the
  204. * case where the user's DllMain() routine fails on a
  205. * Process Attach notification. This does not include
  206. * calling user C++ destructors, etc.
  207. */
  208. /*
  209. * do _onexit/atexit() terminators
  210. * (if there are any)
  211. *
  212. * These terminators MUST be executed in
  213. * reverse order (LIFO)!
  214. *
  215. * NOTE:
  216. * This code assumes that __onexitbegin
  217. * points to the first valid onexit()
  218. * entry and that __onexitend points
  219. * past the last valid entry. If
  220. * __onexitbegin == __onexitend, the
  221. * table is empty and there are no
  222. * routines to call.
  223. */
  224. if (__onexitbegin) {
  225. while ( --__onexitend >= __onexitbegin )
  226. /*
  227. * if current table entry is not
  228. * NULL, call thru it.
  229. */
  230. if ( *__onexitend != NULL )
  231. (**__onexitend)();
  232. /*
  233. * free the block holding onexit table to
  234. * avoid memory leaks. Also zero the ptr
  235. * variable so that it is clearly cleaned up.
  236. */
  237. _free_crt ( __onexitbegin ) ;
  238. __onexitbegin = NULL ;
  239. }
  240. }
  241. return TRUE;
  242. }
  243. BOOL WINAPI _DllMainCRTStartup(
  244. HANDLE hDllHandle,
  245. DWORD dwReason,
  246. LPVOID lpreserved
  247. )
  248. {
  249. BOOL retcode = TRUE;
  250. /*
  251. * If this is a process detach notification, check that there has
  252. * been a prior process attach notification.
  253. */
  254. if ( (dwReason == DLL_PROCESS_DETACH) && (__proc_attached == 0) )
  255. return FALSE;
  256. if ( dwReason == DLL_PROCESS_ATTACH || dwReason == DLL_THREAD_ATTACH )
  257. {
  258. if ( _pRawDllMain )
  259. retcode = (*_pRawDllMain)(hDllHandle, dwReason, lpreserved);
  260. if ( retcode )
  261. retcode = _CRT_INIT(hDllHandle, dwReason, lpreserved);
  262. if ( !retcode )
  263. return FALSE;
  264. }
  265. retcode = DllMain(hDllHandle, dwReason, lpreserved);
  266. if ( (dwReason == DLL_PROCESS_ATTACH) && !retcode )
  267. /*
  268. * The user's DllMain routine returned failure, the C runtime
  269. * needs to be cleaned up. Do this by calling _CRT_INIT again,
  270. * this time imitating DLL_PROCESS_DETACH. Note this will also
  271. * clear the __proc_attached flag so the cleanup will not be
  272. * repeated upon receiving the real process detach notification.
  273. */
  274. _CRT_INIT(hDllHandle, DLL_PROCESS_DETACH, lpreserved);
  275. if ( (dwReason == DLL_PROCESS_DETACH) ||
  276. (dwReason == DLL_THREAD_DETACH) )
  277. {
  278. if ( _CRT_INIT(hDllHandle, dwReason, lpreserved) == FALSE )
  279. retcode = FALSE ;
  280. if ( retcode && _pRawDllMain )
  281. retcode = (*_pRawDllMain)(hDllHandle, dwReason, lpreserved);
  282. }
  283. return retcode ;
  284. }
  285. #endif /* CRTDLL */