Leaked source code of windows server 2003
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.

455 lines
17 KiB

  1. /***
  2. *dllcrt0.c - C runtime initialization routine for a DLL with linked-in C R-T
  3. *
  4. * Copyright (c) 1989-2001, Microsoft Corporation. All rights reserved.
  5. *
  6. *Purpose:
  7. * This the startup routine for a DLL which is linked with its own
  8. * C run-time code. It is similar to the routine _mainCRTStartup()
  9. * in the file CRT0.C, except that there is no main() in a DLL.
  10. *
  11. *Revision History:
  12. * 05-04-92 SKS Based on CRT0.C (start-up code for EXE's)
  13. * 08-26-92 SKS Add _osver, _winver, _winmajor, _winminor
  14. * 09-16-92 SKS This module used to be enabled only in LIBCMT.LIB,
  15. * but it is now enabled for LIBC.LIB as well!
  16. * 09-29-92 SKS _CRT_INIT needs to be WINAPI, not cdecl
  17. * 10-16-92 SKS Call _heap_init before _mtinit (fix copied from CRT0.C)
  18. * 10-24-92 SKS Call to _mtdeletelocks() must be under #ifdef MTHREAD!
  19. * 03-20-93 SKS Remove obsolete variables _osmode, _cpumode, etc.
  20. * 04-06-93 SKS Replace _CRTAPI* with __cdecl
  21. * 04-14-93 SKS _DllMainCRTStartup replaces _CRT_INIT. Also, call
  22. * _mtterm instead of _mtdeletelocks on PROCESS_DETACH
  23. * to do all multi-thread cleanup (e.g. free up TLS index)
  24. * 04-19-93 SKS Remove obsolete variable _atopsp
  25. * 04-20-93 SKS Call _cexit on DLL detach
  26. * 04-20-93 SKS Restore _CRT_INIT, must co-exist with DllMainCRTStartup
  27. * 04-26-93 SKS _mtinit now returns 0 or 1, no longer calls _amsg_exit
  28. * 04-27-93 GJF Removed support for _RT_STACK, _RT_INTDIV,
  29. * _RT_INVALDISP and _RT_NONCONT.
  30. * 05-06-93 SKS Add call to _heap_term to free up all allocated memory
  31. * *and* address space. This must be the last thing done.
  32. * 06-08-93 GJF Added __proc_attached flag.
  33. * 06-08-93 SKS Clean up failure handling in _CRT_INIT
  34. * 11-05-93 CFW Undefine GetEnviromentStrings.
  35. * 11-09-93 GJF Added call to __initmbctable (must happen before args
  36. * and env strings are processed).
  37. * 11-09-93 GJF Added (restored) support for NT SDK builds. Also,
  38. * replaced MTHREAD with _MT.
  39. * 11-20-93 CFW Wide char enable.
  40. * 11-23-93 CFW GetEnviromentStrings undef moved to internal.h.
  41. * 11-29-93 CFW Wide environment.
  42. * 12-06-93 CFW Wide char enable.
  43. * 12-13-93 SKS Free up per-thread CRT data on DLL_THREAD_DETACH
  44. * using a call to _freeptd() in _CRT_INIT()
  45. * 03-30-93 CFW Use __crtXXX calls for Unicode model.
  46. * 04-08-93 CFW Move __crtXXX calls past initialization.
  47. * 06-08-94 SKS Add functn pointer _pRawDllMain, called around DllMain.
  48. * 09-06-94 CFW Remove _MBCS_OS switch.
  49. * 09-06-94 GJF Added __error_mode and __app_type.
  50. * 09-15-94 SKS Move #ifndef directives to after file header comment
  51. * 12-27-94 CFW Remove unused _wDll support.
  52. * 01-16-95 CFW Set default debug output for console.
  53. * 02-22-95 JCF Spliced _WIN32 & Mac versions.
  54. * 03-10-95 JCF Return the user error from DllInit instead of noErr.
  55. * 03-28-95 BWT Fail if unable to retrieve cmdline or envptr (fixes
  56. * stress bug).
  57. * 04-06-95 CFW Set default debug output for Mac, dump leaks for user
  58. * DLL.
  59. * 04-06-95 CFW Use __crtGetEnvironmentStringsA.
  60. * 04-12-95 CFW __crtGetEnvironmentStringsA must be after mtinit().
  61. * 04-14-95 CFW env, arg test must also be.
  62. * 04-26-95 CFW Change default debug output for Mac to debugger.
  63. * 05-23-95 CFW Dump memory leaks before mtterm().
  64. * 06-27-95 CFW Always set __app_type.
  65. * 06-28-95 GJF Added call to _ioterm() to clean up lowio at DLL
  66. * unload time.
  67. * 07-04-95 GJF Interface to __crtGetEnvironmentStrings and _setenvp
  68. * changes slightly.
  69. * 07-07-95 CFW Simplify default report mode scheme.
  70. * 04-23-96 GJF Check for failure of heap initialization.
  71. * 05-14-96 GJF Changed how failure during process attach is handled.
  72. * 02-18-97 GJF Removed obsolete Win32s and PharLap TNT support. Also,
  73. * some cosmetic changes.
  74. * 07-24-97 GJF Minor changes to support stubbing out arg and env
  75. * processing, and our heap manager.
  76. * 10-02-98 GJF Use GetVersionEx instead of GetVersion and store OS ID
  77. * in _osplatform.
  78. * 11-13-98 KBF Moved RTC_Initialize from _cinit to after _heap_init.
  79. * 05-11-99 KBF Wrap RTC support in #ifdef.
  80. * 05-17-99 PML Remove all Macintosh support.
  81. * 02-02-00 GB Added ATTACH_THREAD support for _CRT_INIT where we
  82. * initialise per thread data so that in case where we
  83. * are short of memory, we don't have to kill the whole
  84. * process for inavailablity of space.
  85. * 08-22-00 GB Fixed potentia leak of ptd in CRT_INIT
  86. * 03-16-01 PML _alloca the OSVERSIONINFO so /GS can work (vs7#224261)
  87. * 03-26-01 PML Use GetVersionExA, not GetVersionEx (vs7#230286)
  88. * 03-27-01 PML Fail DLL load instead of calling _amsg_exit (vs7#231220)
  89. * 10-16-01 GB Added fiber support
  90. * 02-20-02 BWT prefast fixes - don't use alloca
  91. * 06-12-02 BWT Don't bother with io/mt/heap term if the process is shutting down.
  92. *
  93. *******************************************************************************/
  94. #ifndef _POSIX_ /* not built for POSIX */
  95. #ifndef CRTDLL /* not built for CRTDLL */
  96. #include <cruntime.h>
  97. #include <dos.h>
  98. #include <internal.h>
  99. #include <mtdll.h>
  100. #include <stdlib.h>
  101. #include <string.h>
  102. #include <rterr.h>
  103. #include <oscalls.h>
  104. #define _DECL_DLLMAIN /* enable prototypes for DllMain and _CRT_INIT */
  105. #include <process.h>
  106. #include <awint.h>
  107. #include <tchar.h>
  108. #include <dbgint.h>
  109. #include <rtcapi.h>
  110. /*
  111. * flag set iff _CRTDLL_INIT was called with DLL_PROCESS_ATTACH
  112. */
  113. static int __proc_attached = 0;
  114. /*
  115. * command line, environment, and a few other globals
  116. */
  117. char *_acmdln; /* points to command line */
  118. char *_aenvptr = NULL; /* points to environment block */
  119. wchar_t *_wenvptr = NULL; /* points to wide environment block */
  120. void (__cdecl * _aexit_rtn)(int) = _exit; /* RT message return procedure */
  121. /*
  122. * _error_mode and _apptype, together, determine how error messages are
  123. * written out.
  124. */
  125. int __error_mode = _OUT_TO_DEFAULT;
  126. int __app_type = _UNKNOWN_APP;
  127. /*
  128. * User routine DllMain is called on all notifications
  129. */
  130. extern BOOL WINAPI DllMain(
  131. HANDLE hDllHandle,
  132. DWORD dwReason,
  133. LPVOID lpreserved
  134. ) ;
  135. /* _pRawDllMain MUST be a common variable, not extern nor initialized! */
  136. BOOL (WINAPI *_pRawDllMain)(HANDLE, DWORD, LPVOID);
  137. /***
  138. *BOOL WINAPI _CRT_INIT(hDllHandle, dwReason, lpreserved) -
  139. * C Run-Time initialization for a DLL linked with a C run-time library.
  140. *
  141. *Purpose:
  142. * This routine does the C run-time initialization or termination.
  143. * For the multi-threaded run-time library, it also cleans up the
  144. * multi-threading locks on DLL termination.
  145. *
  146. *Entry:
  147. *
  148. *Exit:
  149. *
  150. *NOTES:
  151. * This routine must be the entry point for the DLL.
  152. *
  153. *******************************************************************************/
  154. BOOL WINAPI _CRT_INIT(
  155. HANDLE hDllHandle,
  156. DWORD dwReason,
  157. LPVOID lpreserved
  158. )
  159. {
  160. /*
  161. * Start-up code only gets executed when the process is initialized
  162. */
  163. if ( dwReason == DLL_PROCESS_ATTACH )
  164. {
  165. /*
  166. * Dynamically allocate the OSVERSIONINFOA buffer, so we avoid
  167. * triggering the /GS buffer overrun detection. That can't be
  168. * used here, since the guard cookie isn't available until we
  169. * initialize it from here!
  170. */
  171. OSVERSIONINFOA *posvi =
  172. (OSVERSIONINFOA *)HeapAlloc(GetProcessHeap(), 0, sizeof(OSVERSIONINFOA));
  173. if (!posvi) {
  174. return FALSE;
  175. }
  176. /*
  177. * Get the full Win32 version
  178. */
  179. posvi->dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
  180. if ( !GetVersionExA(posvi) ) {
  181. HeapFree(GetProcessHeap(), 0, posvi);
  182. return FALSE;
  183. }
  184. _osplatform = posvi->dwPlatformId;
  185. _winmajor = posvi->dwMajorVersion;
  186. _winminor = posvi->dwMinorVersion;
  187. /*
  188. * The somewhat bizarre calculations of _osver and _winver are
  189. * required for backward compatibility (used to use GetVersion)
  190. */
  191. _osver = (posvi->dwBuildNumber) & 0x07fff;
  192. HeapFree(GetProcessHeap(), 0, posvi);
  193. if ( _osplatform != VER_PLATFORM_WIN32_NT )
  194. _osver |= 0x08000;
  195. _winver = (_winmajor << 8) + _winminor;
  196. #ifdef _MT
  197. if ( !_heap_init(1) ) /* initialize heap */
  198. #else
  199. if ( !_heap_init(0) ) /* initialize heap */
  200. #endif
  201. return FALSE; /* fail to load DLL */
  202. #ifdef _MT
  203. if(!_mtinit()) /* initialize multi-thread */
  204. {
  205. _heap_term(); /* heap is now invalid! */
  206. return FALSE; /* fail to load DLL */
  207. }
  208. #endif /* _MT */
  209. /*
  210. * Initialize the Runtime Checks stuff
  211. */
  212. #ifdef _RTC
  213. _RTC_Initialize();
  214. #endif
  215. _acmdln = (char *)GetCommandLineA();
  216. _aenvptr = (char *)__crtGetEnvironmentStringsA();
  217. if (_ioinit() < 0) { /* initialize lowio */
  218. #ifdef _MT
  219. _mtterm(); /* free TLS index, call _mtdeletelocks() */
  220. #endif /* _MT */
  221. _heap_term(); /* heap is now invalid! */
  222. return FALSE; /* fail to load DLL */
  223. }
  224. if (_setargv() < 0 || /* get cmd line info */
  225. _setenvp() < 0 || /* get environ info */
  226. _cinit() != 0) /* do C data initialize */
  227. {
  228. _ioterm(); /* shut down lowio */
  229. #ifdef _MT
  230. _mtterm(); /* free TLS index, call _mtdeletelocks() */
  231. #endif /* _MT */
  232. _heap_term(); /* heap is now invalid! */
  233. return FALSE; /* fail to load DLL */
  234. }
  235. /*
  236. * increment flag to indicate process attach notification
  237. * has been received
  238. */
  239. __proc_attached++;
  240. }
  241. else if ( dwReason == DLL_PROCESS_DETACH )
  242. {
  243. if ( __proc_attached > 0 )
  244. {
  245. __proc_attached--;
  246. /*
  247. * Any basic clean-up code that goes here must be duplicated
  248. * below in _DllMainCRTStartup for the case where the user's
  249. * DllMain() routine fails on a Process Attach notification.
  250. * This does not include calling user C++ destructors, etc.
  251. */
  252. if ( _C_Termination_Done == FALSE )
  253. _cexit();
  254. #ifdef _DEBUG
  255. /* Dump all memory leaks */
  256. if (_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) & _CRTDBG_LEAK_CHECK_DF)
  257. _CrtDumpMemoryLeaks();
  258. #endif
  259. /*
  260. * What remains is to clean up the system resources we have
  261. * used (handles, critical sections, memory,...,etc.). This
  262. * needs to be done if the whole process is NOT terminating.
  263. */
  264. if ( lpreserved == NULL )
  265. {
  266. /*
  267. * The process is NOT terminating so we must clean up...
  268. */
  269. /* Shut down lowio */
  270. _ioterm();
  271. #ifdef _MT
  272. _mtterm();
  273. #endif
  274. /* This should be the last thing the C run-time does */
  275. _heap_term(); /* heap is now invalid! */
  276. }
  277. }
  278. else
  279. /* no prior process attach, just return */
  280. return FALSE;
  281. }
  282. #ifdef _MT
  283. else if ( dwReason == DLL_THREAD_ATTACH )
  284. {
  285. _ptiddata ptd;
  286. if ( ((ptd = _calloc_crt(1, sizeof(struct _tiddata))) != NULL))
  287. {
  288. if (FLS_SETVALUE(__tlsindex, (LPVOID)ptd) ) {
  289. /*
  290. * Initialize of per-thread data
  291. */
  292. _initptd(ptd);
  293. ptd->_tid = GetCurrentThreadId();
  294. ptd->_thandle = (uintptr_t)(-1);
  295. } else
  296. {
  297. _free_crt(ptd);
  298. return FALSE;
  299. }
  300. } else
  301. {
  302. return FALSE;
  303. }
  304. }
  305. else if ( dwReason == DLL_THREAD_DETACH )
  306. {
  307. _freeptd(NULL); /* free up per-thread CRT data */
  308. }
  309. #endif
  310. return TRUE ;
  311. }
  312. /***
  313. *BOOL WINAPI _DllMainCRTStartup(hDllHandle, dwReason, lpreserved) -
  314. * C Run-Time initialization for a DLL linked with a C run-time library.
  315. *
  316. *Purpose:
  317. * This routine does the C run-time initialization or termination
  318. * and then calls the user code notification handler "DllMain".
  319. * For the multi-threaded run-time library, it also cleans up the
  320. * multi-threading locks on DLL termination.
  321. *
  322. *Entry:
  323. *
  324. *Exit:
  325. *
  326. *NOTES:
  327. * This routine is the preferred entry point. _CRT_INIT may also be
  328. * used, or the user may supply his/her own entry and call _CRT_INIT
  329. * from within it, but this is not the preferred method.
  330. *
  331. *******************************************************************************/
  332. BOOL WINAPI _DllMainCRTStartup(
  333. HANDLE hDllHandle,
  334. DWORD dwReason,
  335. LPVOID lpreserved
  336. )
  337. {
  338. BOOL retcode = TRUE;
  339. /*
  340. * If this is a process detach notification, check that there has
  341. * has been a prior process attach notification.
  342. */
  343. if ( (dwReason == DLL_PROCESS_DETACH) && (__proc_attached == 0) )
  344. /*
  345. * no prior process attach notification. just return
  346. * without doing anything.
  347. */
  348. return FALSE;
  349. if ( dwReason == DLL_PROCESS_ATTACH || dwReason == DLL_THREAD_ATTACH )
  350. {
  351. if ( _pRawDllMain )
  352. retcode = (*_pRawDllMain)(hDllHandle, dwReason, lpreserved);
  353. if ( retcode )
  354. retcode = _CRT_INIT(hDllHandle, dwReason, lpreserved);
  355. if ( !retcode )
  356. return FALSE;
  357. }
  358. retcode = DllMain(hDllHandle, dwReason, lpreserved);
  359. if ( (dwReason == DLL_PROCESS_ATTACH) && !retcode )
  360. /*
  361. * The user's DllMain routine returned failure, the C runtime
  362. * needs to be cleaned up. Do this by calling _CRT_INIT again,
  363. * this time imitating DLL_PROCESS_DETACH. Note this will also
  364. * clear the __proc_attached flag so the cleanup will not be
  365. * repeated upon receiving the real process detach notification.
  366. */
  367. _CRT_INIT(hDllHandle, DLL_PROCESS_DETACH, lpreserved);
  368. if ( (dwReason == DLL_PROCESS_DETACH) ||
  369. (dwReason == DLL_THREAD_DETACH) )
  370. {
  371. if ( _CRT_INIT(hDllHandle, dwReason, lpreserved) == FALSE )
  372. retcode = FALSE ;
  373. if ( retcode && _pRawDllMain )
  374. retcode = (*_pRawDllMain)(hDllHandle, dwReason, lpreserved);
  375. }
  376. return retcode ;
  377. }
  378. /***
  379. *_amsg_exit(rterrnum) - Fast exit fatal errors
  380. *
  381. *Purpose:
  382. * Exit the program with error code of 255 and appropriate error
  383. * message.
  384. *
  385. *Entry:
  386. * int rterrnum - error message number (amsg_exit only).
  387. *
  388. *Exit:
  389. * Calls exit() (for integer divide-by-0) or _exit() indirectly
  390. * through _aexit_rtn [amsg_exit].
  391. * For multi-thread: calls _exit() function
  392. *
  393. *Exceptions:
  394. *
  395. *******************************************************************************/
  396. void __cdecl _amsg_exit (
  397. int rterrnum
  398. )
  399. {
  400. if ( (__error_mode == _OUT_TO_STDERR) || ((__error_mode ==
  401. _OUT_TO_DEFAULT) && (__app_type == _CONSOLE_APP)) )
  402. _FF_MSGBANNER(); /* write run-time error banner */
  403. _NMSG_WRITE(rterrnum); /* write message */
  404. _aexit_rtn(255); /* normally _exit(255) */
  405. }
  406. #endif /* CRTDLL */
  407. #endif /* _POSIX_ */