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.

591 lines
19 KiB

  1. /***
  2. *crtexe.c - Initialization for console EXE using CRT DLL
  3. *
  4. * Copyright (c) 1991-2001, Microsoft Corporation. All rights reserved.
  5. *
  6. *Purpose:
  7. * This is the actual startup routine for apps linking to the CRT DLL.
  8. * It calls the user's main routine [w]main() or [w]WinMain after
  9. * performing C Run-Time Library initialization.
  10. *
  11. * With ifdefs, this source file also provides the source code for:
  12. * wcrtexe.c the startup routine for console apps with wide chars
  13. * crtexew.c the startup routine for Windows apps
  14. * wcrtexew.c the startup routine for Windows apps with wide chars
  15. *
  16. *Revision History:
  17. * 08-12-91 GJF Module created.
  18. * 01-05-92 GJF Substantially revised
  19. * 01-17-92 GJF Restored Stevewo's scheme for unhandled exceptions.
  20. * 01-29-92 GJF Added support for linked-in options (equivalents of
  21. * binmode.obj, commode.obj and setargv.obj).
  22. * 04-17-92 SKS Add call to _initterm() to do C++ constructors (I386)
  23. * 08-01-92 SRW winxcpt.h replaced bu excpt.h which is included by
  24. * oscalls.h
  25. * 09-16-92 SKS Prepare for C8 C++ for MIPS by calling C++ constructors
  26. * 04-02-93 SKS Change try/except to __try/__except
  27. * 04-06-93 SKS Replace _CRTAPI* with _cdecl
  28. * Change __GetMainArgs to __getmainargs
  29. * Change fmode/commode implementation to reflect the
  30. * the change to _declspec(dllimport) for imported data.
  31. * 04-12-93 CFW Added xia..xiz initializers and initializer call.
  32. * 04-26-93 GJF Made lpszCommandLine (unsigned char *) to deal with
  33. * chars > 127 in the command line.
  34. * 04-27-93 GJF Removed support for _RT_STACK, _RT_INTDIV,
  35. * _RT_INVALDISP and _RT_NONCONT.
  36. * 05-14-93 GJF Added support for quoted program names.
  37. * 05-24-93 SKS Add support for special versions of _onexit/atexit
  38. * which do one thing for EXE's and another for DLLs.
  39. * 10-19-93 CFW MIPS support for _imp__xxx.
  40. * 10-21-93 GJF Added support for NT's crtdll.dll.
  41. * 11-08-93 GJF Guard the initialization code with the __try -
  42. * __except statement (esp., C++ constructors for static
  43. * objects).
  44. * 11-09-93 GJF Replaced PF with _PVFV (defined in internal.h).
  45. * 11-23-93 CFW Wide char enable.
  46. * 12-07-93 CFW Change _TCHAR to _TSCHAR.
  47. * 01-04-94 CFW Pass copy of environment to main.
  48. * 01-11-94 GJF Call __GetMainArgs instead of __getmainargs for NT
  49. * SDK build (same function, different name)
  50. * 01-28-94 CFW Move environment copying to setenv.c.
  51. * 03-04-94 SKS Remove __setargv from this module to avoid link-time
  52. * problems compiling -MD and linking with setargv.obj.
  53. * static _dowildcard becomes an extern. Add another
  54. * parameter to _*getmainargs (_newmode).
  55. * NOTE: These channges do NOT apply to the _NTSDK.
  56. * 03-28-94 SKS Add call to _setdefaultprecision for X86 (not _NTSDK)
  57. * 04-01-94 GJF Moved declaration of __[w]initenv to internal.h.
  58. * 04-06-94 GJF _IMP___FMODE, _IMP___COMMODE now evaluate to
  59. * dereferences of function returns for _M_IX86 (for
  60. * compatability with Win32s version of msvcrt*.dll).
  61. * 04-25-94 CFW wWinMain has Unicode args.
  62. * 05-16-94 SKS Get StartupInfo to give correct nCmdShow parameter
  63. * to (_w)WinMain() (was ALWAYS passing SW_SHOWDEFAULT).
  64. * 08-04-94 GJF Added support for user-supplied _matherr routine
  65. * 09-06-94 GJF Added code to set __app_type properly.
  66. * 10-04-94 BWT Fix _NTSDK build
  67. * 02-22-95 JWM Spliced in PMAC code.
  68. * 05-24-95 CFW Official ANSI C++ new handler added.
  69. * 07-24-95 CFW Change PMac onexit malloc to _malloc_crt.
  70. * 06-27-96 GJF Replaced defined(_WIN32) wint !defined(_MAC). Cleaned
  71. * up the format a bit.
  72. * 08-01-96 RDK For PMac, set onexit table pointers to -1 to parallel
  73. * x86 functionality.
  74. * 04-28-99 PML Wrap __declspec(allocate()) in _CRTALLOC macro.
  75. * 05-11-99 KBF Wrap RTC support in #ifdef.
  76. * 05-17-99 PML Remove all Macintosh support.
  77. * 11-13-99 PML Create 4 new COM+ specific entrypoints which return
  78. * instead of calling exit().
  79. * 11-16-99 PML ... and remove them - linker problems mean new
  80. * entrypoints don't work. Instead, look directly at the
  81. * COM Descriptor Image Directory entry in the optional
  82. * header to see if we are a COM+ app.
  83. * 02-16-00 GB Changed GetModuleHandle to GetModuleHandleA in
  84. * check_complus_app.
  85. * 08-04-00 PML check_complus_app -> check_managed_app (VS7#117746).
  86. * 08-22-00 GB Changed GetModuleHandle to GetModuleHandleA in
  87. * mainCRTStartup().
  88. * 12-09-00 PML Tighten up check_managed_app tests (VS7#167293).
  89. * 03-27-01 PML report _RT_SPACEARG on __[w]getmainargs error
  90. * (VS7#231220).
  91. * 04-30-01 BWT Don't do this for SYSCRT. Need to run against old msvcrt.dll's
  92. * that don't return error.
  93. * Remove _NTSDK.
  94. * 10-11-01 BWT Replace GetModuleHandle(NULL) with &__ImageBase
  95. * 11-21-01 BWT Wrap ansi GetStartupInfo with try/except (it can raise
  96. * exceptions on failure)
  97. *
  98. *******************************************************************************/
  99. #ifdef CRTDLL
  100. /*
  101. * SPECIAL BUILD MACROS! Note that crtexe.c (and crtexew.c) is linked in with
  102. * the client's code. It does not go into crtdll.dll! Therefore, it must be
  103. * built under the _DLL switch (like user code) and CRTDLL must be undefined.
  104. * The symbol SPECIAL_CRTEXE is turned on to suppress the normal CRT DLL
  105. * definition of _fmode and _commode using __declspec(dllexport). Otherwise
  106. * this module would not be able to refer to both the local and DLL versions
  107. * of these two variables.
  108. */
  109. #undef CRTDLL
  110. #undef _DLL
  111. #define _DLL
  112. #define SPECIAL_CRTEXE
  113. #include <cruntime.h>
  114. #include <oscalls.h>
  115. #include <internal.h>
  116. #include <process.h>
  117. #include <math.h>
  118. #include <rterr.h>
  119. #include <stdlib.h>
  120. #include <tchar.h>
  121. #include <rtcapi.h>
  122. #include <sect_attribs.h>
  123. #if defined(_WIN64) && defined(_M_IA64)
  124. #pragma section(".base", long, read, write)
  125. __declspec(allocate(".base"))
  126. extern
  127. IMAGE_DOS_HEADER __ImageBase;
  128. #else
  129. extern
  130. IMAGE_DOS_HEADER __ImageBase;
  131. #endif
  132. /*
  133. * wWinMain is not yet defined in winbase.h. When it is, this should be
  134. * removed.
  135. */
  136. int
  137. WINAPI
  138. wWinMain(
  139. HINSTANCE hInstance,
  140. HINSTANCE hPrevInstance,
  141. LPWSTR lpCmdLine,
  142. int nShowCmd
  143. );
  144. #define SPACECHAR _T(' ')
  145. #define DQUOTECHAR _T('\"')
  146. #ifdef _M_IX86
  147. /*
  148. * The local copy of the Pentium FDIV adjustment flag
  149. * and the address of the flag in MSVCRT*.DLL.
  150. */
  151. extern int _adjust_fdiv;
  152. extern int * _imp___adjust_fdiv;
  153. #endif
  154. /* default floating point precision - X86 only! */
  155. #ifdef _M_IX86
  156. extern void _setdefaultprecision();
  157. #endif
  158. /*
  159. * Declare function used to install a user-supplied _matherr routine.
  160. */
  161. _CRTIMP void __setusermatherr( int (__cdecl *)(struct _exception *) );
  162. /*
  163. * Declare the names of the exports corresponding to _fmode and _commode
  164. */
  165. #ifdef _M_IX86
  166. #define _IMP___FMODE (__p__fmode())
  167. #define _IMP___COMMODE (__p__commode())
  168. #else /* ndef _M_IX86 */
  169. /* assumed to be MIPS or Alpha */
  170. #define _IMP___FMODE __imp__fmode
  171. #define _IMP___COMMODE __imp__commode
  172. #endif /* _M_IX86 */
  173. #if !defined(_M_IX86)
  174. extern int * _IMP___FMODE; /* exported from the CRT DLL */
  175. extern int * _IMP___COMMODE; /* these names are implementation-specific */
  176. #endif
  177. extern int _fmode; /* must match the definition in <stdlib.h> */
  178. extern int _commode; /* must match the definition in <internal.h> */
  179. extern int _dowildcard; /* passed to __getmainargs() */
  180. /*
  181. * Declare/define communal that serves as indicator the default matherr
  182. * routine is being used.
  183. */
  184. int __defaultmatherr;
  185. /*
  186. * routine in DLL to do initialization (in this case, C++ constructors)
  187. */
  188. extern void __cdecl _initterm(_PVFV *, _PVFV *);
  189. /*
  190. * routine to check if this is a managed application
  191. */
  192. static int __cdecl check_managed_app(void);
  193. /*
  194. * pointers to initialization sections
  195. */
  196. extern _CRTALLOC(".CRT$XIA") _PVFV __xi_a[];
  197. extern _CRTALLOC(".CRT$XIZ") _PVFV __xi_z[]; /* C initializers */
  198. extern _CRTALLOC(".CRT$XCA") _PVFV __xc_a[];
  199. extern _CRTALLOC(".CRT$XCZ") _PVFV __xc_z[]; /* C++ initializers */
  200. /*
  201. * Pointers to beginning and end of the table of function pointers manipulated
  202. * by _onexit()/atexit(). The atexit/_onexit code is shared for both EXE's and
  203. * DLL's but different behavior is required. These values are set to -1 to
  204. * mark this module as an EXE.
  205. */
  206. extern _PVFV *__onexitbegin;
  207. extern _PVFV *__onexitend;
  208. /***
  209. *mainCRTStartup(void)
  210. *wmainCRTStartup(void)
  211. *WinMainCRTStartup(void)
  212. *wWinMainCRTStartup(void)
  213. *
  214. *Purpose:
  215. * These routines do the C runtime initialization, call the appropriate
  216. * user entry function, and handle termination cleanup. For a managed
  217. * app, they then return the exit code back to the calling routine, which
  218. * is the managed startup code. For an unmanaged app, they call exit and
  219. * never return.
  220. *
  221. * Function: User entry called:
  222. * mainCRTStartup main
  223. * wmainCRTStartup wmain
  224. * WinMainCRTStartup WinMain
  225. * wWinMainCRTStartup wWinMain
  226. *
  227. *Entry:
  228. *
  229. *Exit:
  230. * Managed app: return value from main() et al, or the exception code if
  231. * execution was terminated by the __except guarding the call
  232. * to main().
  233. * Unmanaged app: never return.
  234. *
  235. *******************************************************************************/
  236. #ifdef _WINMAIN_
  237. #ifdef WPRFLAG
  238. int wWinMainCRTStartup(
  239. #else
  240. int WinMainCRTStartup(
  241. #endif
  242. #else /* ndef _WINMAIN_ */
  243. #ifdef WPRFLAG
  244. int wmainCRTStartup(
  245. #else
  246. int mainCRTStartup(
  247. #endif
  248. #endif /* _WINMAIN_ */
  249. void
  250. )
  251. {
  252. int argc; /* three standard arguments to main */
  253. _TSCHAR **argv;
  254. _TSCHAR **envp;
  255. int argret;
  256. int mainret;
  257. int managedapp;
  258. _startupinfo startinfo;
  259. #ifdef _WINMAIN_
  260. _TUCHAR *lpszCommandLine;
  261. STARTUPINFO StartupInfo;
  262. #ifdef WPRFLAG
  263. GetStartupInfo(&StartupInfo);
  264. #else
  265. __try {
  266. GetStartupInfo( &StartupInfo );
  267. } __except(EXCEPTION_EXECUTE_HANDLER) {
  268. return 255;
  269. }
  270. #endif
  271. #endif
  272. /*
  273. * Determine if this is a managed application
  274. */
  275. managedapp = check_managed_app();
  276. /*
  277. * Guard the initialization code and the call to user's main, or
  278. * WinMain, function in a __try/__except statement.
  279. */
  280. __try {
  281. /*
  282. * Set __app_type properly
  283. */
  284. #ifdef _WINMAIN_
  285. __set_app_type(_GUI_APP);
  286. #else
  287. __set_app_type(_CONSOLE_APP);
  288. #endif
  289. /*
  290. * Mark this module as an EXE file so that atexit/_onexit
  291. * will do the right thing when called, including for C++
  292. * d-tors.
  293. */
  294. __onexitbegin = __onexitend = (_PVFV *)(-1);
  295. /*
  296. * Propogate the _fmode and _commode variables to the DLL
  297. */
  298. *_IMP___FMODE = _fmode;
  299. *_IMP___COMMODE = _commode;
  300. #ifdef _M_IX86
  301. /*
  302. * Set the local copy of the Pentium FDIV adjustment flag
  303. */
  304. _adjust_fdiv = * _imp___adjust_fdiv;
  305. #endif
  306. /*
  307. * Run the RTC initialization code for this DLL
  308. */
  309. #ifdef _RTC
  310. _RTC_Initialize();
  311. #endif
  312. /*
  313. * Call _setargv(), which will trigger a call to __setargv() if
  314. * SETARGV.OBJ is linked with the EXE. If SETARGV.OBJ is not
  315. * linked with the EXE, a dummy _setargv() will be called.
  316. */
  317. #ifdef WPRFLAG
  318. _wsetargv();
  319. #else
  320. _setargv();
  321. #endif
  322. /*
  323. * If the user has supplied a _matherr routine then set
  324. * __pusermatherr to point to it.
  325. */
  326. if ( !__defaultmatherr )
  327. __setusermatherr(_matherr);
  328. #ifdef _M_IX86
  329. _setdefaultprecision();
  330. #endif
  331. /*
  332. * Do runtime startup initializers.
  333. *
  334. * Note: the only possible entry we'll be executing here is for
  335. * __lconv_init, pulled in from charmax.obj only if the EXE was
  336. * compiled with -J. All other .CRT$XI* initializers are only
  337. * run as part of the CRT itself, and so for the CRT DLL model
  338. * are not found in the EXE. For that reason, we call _initterm,
  339. * not _initterm_e, because __lconv_init will never return failure,
  340. * and _initterm_e is not exported from the CRT DLL.
  341. *
  342. * Note further that, when using the CRT DLL, executing the
  343. * .CRT$XI* initializers is only done for an EXE, not for a DLL
  344. * using the CRT DLL. That is to make sure the -J setting for
  345. * the EXE is not overriden by that of any DLL.
  346. */
  347. _initterm( __xi_a, __xi_z );
  348. #ifdef _RTC
  349. atexit(_RTC_Terminate);
  350. #endif
  351. /*
  352. * Get the arguments for the call to main. Note this must be
  353. * done explicitly, rather than as part of the dll's
  354. * initialization, to implement optional expansion of wild
  355. * card chars in filename args
  356. */
  357. startinfo.newmode = _newmode;
  358. #ifdef ANSI_NEW_HANDLER
  359. startinfo.newh = _defnewh;
  360. #endif /* ANSI_NEW_HANDLER */
  361. #ifdef WPRFLAG
  362. argret = __wgetmainargs(&argc, &argv, &envp,
  363. _dowildcard, &startinfo);
  364. #else
  365. argret = __getmainargs(&argc, &argv, &envp,
  366. _dowildcard, &startinfo);
  367. #endif
  368. #ifndef _SYSCRT
  369. if (argret < 0)
  370. _amsg_exit(_RT_SPACEARG);
  371. #endif
  372. /*
  373. * do C++ constructors (initializers) specific to this EXE
  374. */
  375. _initterm( __xc_a, __xc_z );
  376. #ifdef _WINMAIN_
  377. /*
  378. * Skip past program name (first token in command line).
  379. * Check for and handle quoted program name.
  380. */
  381. #ifdef WPRFLAG
  382. /* OS may not support "W" flavors */
  383. if (_wcmdln == NULL)
  384. return 255;
  385. lpszCommandLine = (wchar_t *)_wcmdln;
  386. #else
  387. lpszCommandLine = (unsigned char *)_acmdln;
  388. #endif
  389. if ( *lpszCommandLine == DQUOTECHAR ) {
  390. /*
  391. * Scan, and skip over, subsequent characters until
  392. * another double-quote or a null is encountered.
  393. */
  394. while ( *++lpszCommandLine && (*lpszCommandLine
  395. != DQUOTECHAR) );
  396. /*
  397. * If we stopped on a double-quote (usual case), skip
  398. * over it.
  399. */
  400. if ( *lpszCommandLine == DQUOTECHAR )
  401. lpszCommandLine++;
  402. }
  403. else {
  404. while (*lpszCommandLine > SPACECHAR)
  405. lpszCommandLine++;
  406. }
  407. /*
  408. * Skip past any white space preceeding the second token.
  409. */
  410. while (*lpszCommandLine && (*lpszCommandLine <= SPACECHAR)) {
  411. lpszCommandLine++;
  412. }
  413. #ifdef WPRFLAG
  414. mainret = wWinMain(
  415. #else
  416. mainret = WinMain(
  417. #endif
  418. (HINSTANCE)&__ImageBase,
  419. NULL,
  420. lpszCommandLine,
  421. StartupInfo.dwFlags & STARTF_USESHOWWINDOW
  422. ? StartupInfo.wShowWindow
  423. : SW_SHOWDEFAULT
  424. );
  425. #else /* _WINMAIN_ */
  426. #ifdef WPRFLAG
  427. __winitenv = envp;
  428. mainret = wmain(argc, argv, envp);
  429. #else
  430. __initenv = envp;
  431. mainret = main(argc, argv, envp);
  432. #endif
  433. #endif /* _WINMAIN_ */
  434. if ( !managedapp )
  435. exit(mainret);
  436. _cexit();
  437. }
  438. __except ( _XcptFilter(GetExceptionCode(), GetExceptionInformation()) )
  439. {
  440. /*
  441. * Should never reach here
  442. */
  443. mainret = GetExceptionCode();
  444. if ( !managedapp )
  445. _exit(mainret);
  446. _c_exit();
  447. } /* end of try - except */
  448. return mainret;
  449. }
  450. /***
  451. *check_managed_app() - Check for a managed executable
  452. *
  453. *Purpose:
  454. * Determine if the EXE the startup code is linked into is a managed app
  455. * by looking for the COM Runtime Descriptor in the Image Data Directory
  456. * of the PE or PE+ header.
  457. *
  458. *Entry:
  459. * None
  460. *
  461. *Exit:
  462. * 1 if managed app, 0 if not.
  463. *
  464. *Exceptions:
  465. *
  466. *******************************************************************************/
  467. static int __cdecl check_managed_app (
  468. void
  469. )
  470. {
  471. PIMAGE_DOS_HEADER pDOSHeader;
  472. PIMAGE_NT_HEADERS pPEHeader;
  473. PIMAGE_OPTIONAL_HEADER32 pNTHeader32;
  474. PIMAGE_OPTIONAL_HEADER64 pNTHeader64;
  475. pDOSHeader = (PIMAGE_DOS_HEADER)&__ImageBase;
  476. if ( pDOSHeader->e_magic != IMAGE_DOS_SIGNATURE )
  477. return 0;
  478. pPEHeader = (PIMAGE_NT_HEADERS)((char *)pDOSHeader +
  479. pDOSHeader->e_lfanew);
  480. if ( pPEHeader->Signature != IMAGE_NT_SIGNATURE )
  481. return 0;
  482. pNTHeader32 = (PIMAGE_OPTIONAL_HEADER32)&pPEHeader->OptionalHeader;
  483. switch ( pNTHeader32->Magic ) {
  484. case IMAGE_NT_OPTIONAL_HDR32_MAGIC:
  485. /* PE header */
  486. if ( pNTHeader32->NumberOfRvaAndSizes <=
  487. IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR )
  488. return 0;
  489. return !! pNTHeader32 ->
  490. DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR] .
  491. VirtualAddress;
  492. case IMAGE_NT_OPTIONAL_HDR64_MAGIC:
  493. /* PE+ header */
  494. pNTHeader64 = (PIMAGE_OPTIONAL_HEADER64)pNTHeader32;
  495. if ( pNTHeader64->NumberOfRvaAndSizes <=
  496. IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR )
  497. return 0;
  498. return !! pNTHeader64 ->
  499. DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR] .
  500. VirtualAddress;
  501. }
  502. /* Not PE or PE+, so not managed */
  503. return 0;
  504. }
  505. #endif /* CRTDLL */