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.

570 lines
18 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. *
  95. *******************************************************************************/
  96. #ifdef CRTDLL
  97. /*
  98. * SPECIAL BUILD MACROS! Note that crtexe.c (and crtexew.c) is linked in with
  99. * the client's code. It does not go into crtdll.dll! Therefore, it must be
  100. * built under the _DLL switch (like user code) and CRTDLL must be undefined.
  101. * The symbol SPECIAL_CRTEXE is turned on to suppress the normal CRT DLL
  102. * definition of _fmode and _commode using __declspec(dllexport). Otherwise
  103. * this module would not be able to refer to both the local and DLL versions
  104. * of these two variables.
  105. */
  106. #undef CRTDLL
  107. #undef _DLL
  108. #define _DLL
  109. #define SPECIAL_CRTEXE
  110. #include <cruntime.h>
  111. #include <oscalls.h>
  112. #include <internal.h>
  113. #include <process.h>
  114. #include <math.h>
  115. #include <rterr.h>
  116. #include <stdlib.h>
  117. #include <tchar.h>
  118. #include <rtcapi.h>
  119. #include <sect_attribs.h>
  120. /*
  121. * wWinMain is not yet defined in winbase.h. When it is, this should be
  122. * removed.
  123. */
  124. int
  125. WINAPI
  126. wWinMain(
  127. HINSTANCE hInstance,
  128. HINSTANCE hPrevInstance,
  129. LPWSTR lpCmdLine,
  130. int nShowCmd
  131. );
  132. #define SPACECHAR _T(' ')
  133. #define DQUOTECHAR _T('\"')
  134. #ifdef _M_IX86
  135. /*
  136. * The local copy of the Pentium FDIV adjustment flag
  137. * and the address of the flag in MSVCRT*.DLL.
  138. */
  139. extern int _adjust_fdiv;
  140. extern int * _imp___adjust_fdiv;
  141. #endif
  142. /* default floating point precision - X86 only! */
  143. #ifdef _M_IX86
  144. extern void _setdefaultprecision();
  145. #endif
  146. /*
  147. * Declare function used to install a user-supplied _matherr routine.
  148. */
  149. _CRTIMP void __setusermatherr( int (__cdecl *)(struct _exception *) );
  150. /*
  151. * Declare the names of the exports corresponding to _fmode and _commode
  152. */
  153. #ifdef _M_IX86
  154. #define _IMP___FMODE (__p__fmode())
  155. #define _IMP___COMMODE (__p__commode())
  156. #else /* ndef _M_IX86 */
  157. /* assumed to be MIPS or Alpha */
  158. #define _IMP___FMODE __imp__fmode
  159. #define _IMP___COMMODE __imp__commode
  160. #endif /* _M_IX86 */
  161. #if !defined(_M_IX86)
  162. extern int * _IMP___FMODE; /* exported from the CRT DLL */
  163. extern int * _IMP___COMMODE; /* these names are implementation-specific */
  164. #endif
  165. extern int _fmode; /* must match the definition in <stdlib.h> */
  166. extern int _commode; /* must match the definition in <internal.h> */
  167. extern int _dowildcard; /* passed to __getmainargs() */
  168. /*
  169. * Declare/define communal that serves as indicator the default matherr
  170. * routine is being used.
  171. */
  172. int __defaultmatherr;
  173. /*
  174. * routine in DLL to do initialization (in this case, C++ constructors)
  175. */
  176. extern void __cdecl _initterm(_PVFV *, _PVFV *);
  177. /*
  178. * routine to check if this is a managed application
  179. */
  180. static int __cdecl check_managed_app(void);
  181. /*
  182. * pointers to initialization sections
  183. */
  184. extern _CRTALLOC(".CRT$XIA") _PVFV __xi_a[];
  185. extern _CRTALLOC(".CRT$XIZ") _PVFV __xi_z[]; /* C initializers */
  186. extern _CRTALLOC(".CRT$XCA") _PVFV __xc_a[];
  187. extern _CRTALLOC(".CRT$XCZ") _PVFV __xc_z[]; /* C++ initializers */
  188. /*
  189. * Pointers to beginning and end of the table of function pointers manipulated
  190. * by _onexit()/atexit(). The atexit/_onexit code is shared for both EXE's and
  191. * DLL's but different behavior is required. These values are set to -1 to
  192. * mark this module as an EXE.
  193. */
  194. extern _PVFV *__onexitbegin;
  195. extern _PVFV *__onexitend;
  196. /***
  197. *mainCRTStartup(void)
  198. *wmainCRTStartup(void)
  199. *WinMainCRTStartup(void)
  200. *wWinMainCRTStartup(void)
  201. *
  202. *Purpose:
  203. * These routines do the C runtime initialization, call the appropriate
  204. * user entry function, and handle termination cleanup. For a managed
  205. * app, they then return the exit code back to the calling routine, which
  206. * is the managed startup code. For an unmanaged app, they call exit and
  207. * never return.
  208. *
  209. * Function: User entry called:
  210. * mainCRTStartup main
  211. * wmainCRTStartup wmain
  212. * WinMainCRTStartup WinMain
  213. * wWinMainCRTStartup wWinMain
  214. *
  215. *Entry:
  216. *
  217. *Exit:
  218. * Managed app: return value from main() et al, or the exception code if
  219. * execution was terminated by the __except guarding the call
  220. * to main().
  221. * Unmanaged app: never return.
  222. *
  223. *******************************************************************************/
  224. #ifdef _WINMAIN_
  225. #ifdef WPRFLAG
  226. int wWinMainCRTStartup(
  227. #else
  228. int WinMainCRTStartup(
  229. #endif
  230. #else /* ndef _WINMAIN_ */
  231. #ifdef WPRFLAG
  232. int wmainCRTStartup(
  233. #else
  234. int mainCRTStartup(
  235. #endif
  236. #endif /* _WINMAIN_ */
  237. void
  238. )
  239. {
  240. int argc; /* three standard arguments to main */
  241. _TSCHAR **argv;
  242. _TSCHAR **envp;
  243. int argret;
  244. int mainret;
  245. int managedapp;
  246. #ifdef _WINMAIN_
  247. _TUCHAR *lpszCommandLine;
  248. STARTUPINFO StartupInfo;
  249. #endif
  250. _startupinfo startinfo;
  251. /*
  252. * Determine if this is a managed application
  253. */
  254. managedapp = check_managed_app();
  255. /*
  256. * Guard the initialization code and the call to user's main, or
  257. * WinMain, function in a __try/__except statement.
  258. */
  259. __try {
  260. /*
  261. * Set __app_type properly
  262. */
  263. #ifdef _WINMAIN_
  264. __set_app_type(_GUI_APP);
  265. #else
  266. __set_app_type(_CONSOLE_APP);
  267. #endif
  268. /*
  269. * Mark this module as an EXE file so that atexit/_onexit
  270. * will do the right thing when called, including for C++
  271. * d-tors.
  272. */
  273. __onexitbegin = __onexitend = (_PVFV *)(-1);
  274. /*
  275. * Propogate the _fmode and _commode variables to the DLL
  276. */
  277. *_IMP___FMODE = _fmode;
  278. *_IMP___COMMODE = _commode;
  279. #ifdef _M_IX86
  280. /*
  281. * Set the local copy of the Pentium FDIV adjustment flag
  282. */
  283. _adjust_fdiv = * _imp___adjust_fdiv;
  284. #endif
  285. /*
  286. * Run the RTC initialization code for this DLL
  287. */
  288. #ifdef _RTC
  289. _RTC_Initialize();
  290. #endif
  291. /*
  292. * Call _setargv(), which will trigger a call to __setargv() if
  293. * SETARGV.OBJ is linked with the EXE. If SETARGV.OBJ is not
  294. * linked with the EXE, a dummy _setargv() will be called.
  295. */
  296. #ifdef WPRFLAG
  297. _wsetargv();
  298. #else
  299. _setargv();
  300. #endif
  301. /*
  302. * If the user has supplied a _matherr routine then set
  303. * __pusermatherr to point to it.
  304. */
  305. if ( !__defaultmatherr )
  306. __setusermatherr(_matherr);
  307. #ifdef _M_IX86
  308. _setdefaultprecision();
  309. #endif
  310. /*
  311. * Do runtime startup initializers.
  312. *
  313. * Note: the only possible entry we'll be executing here is for
  314. * __lconv_init, pulled in from charmax.obj only if the EXE was
  315. * compiled with -J. All other .CRT$XI* initializers are only
  316. * run as part of the CRT itself, and so for the CRT DLL model
  317. * are not found in the EXE. For that reason, we call _initterm,
  318. * not _initterm_e, because __lconv_init will never return failure,
  319. * and _initterm_e is not exported from the CRT DLL.
  320. *
  321. * Note further that, when using the CRT DLL, executing the
  322. * .CRT$XI* initializers is only done for an EXE, not for a DLL
  323. * using the CRT DLL. That is to make sure the -J setting for
  324. * the EXE is not overriden by that of any DLL.
  325. */
  326. _initterm( __xi_a, __xi_z );
  327. #ifdef _RTC
  328. atexit(_RTC_Terminate);
  329. #endif
  330. /*
  331. * Get the arguments for the call to main. Note this must be
  332. * done explicitly, rather than as part of the dll's
  333. * initialization, to implement optional expansion of wild
  334. * card chars in filename args
  335. */
  336. startinfo.newmode = _newmode;
  337. #ifdef ANSI_NEW_HANDLER
  338. startinfo.newh = _defnewh;
  339. #endif /* ANSI_NEW_HANDLER */
  340. #ifdef WPRFLAG
  341. argret = __wgetmainargs(&argc, &argv, &envp,
  342. _dowildcard, &startinfo);
  343. #else
  344. argret = __getmainargs(&argc, &argv, &envp,
  345. _dowildcard, &startinfo);
  346. #endif
  347. #ifndef _SYSCRT
  348. if (argret < 0)
  349. _amsg_exit(_RT_SPACEARG);
  350. #endif
  351. /*
  352. * do C++ constructors (initializers) specific to this EXE
  353. */
  354. _initterm( __xc_a, __xc_z );
  355. #ifdef _WINMAIN_
  356. /*
  357. * Skip past program name (first token in command line).
  358. * Check for and handle quoted program name.
  359. */
  360. #ifdef WPRFLAG
  361. /* OS may not support "W" flavors */
  362. if (_wcmdln == NULL)
  363. return 255;
  364. lpszCommandLine = (wchar_t *)_wcmdln;
  365. #else
  366. lpszCommandLine = (unsigned char *)_acmdln;
  367. #endif
  368. if ( *lpszCommandLine == DQUOTECHAR ) {
  369. /*
  370. * Scan, and skip over, subsequent characters until
  371. * another double-quote or a null is encountered.
  372. */
  373. while ( *++lpszCommandLine && (*lpszCommandLine
  374. != DQUOTECHAR) );
  375. /*
  376. * If we stopped on a double-quote (usual case), skip
  377. * over it.
  378. */
  379. if ( *lpszCommandLine == DQUOTECHAR )
  380. lpszCommandLine++;
  381. }
  382. else {
  383. while (*lpszCommandLine > SPACECHAR)
  384. lpszCommandLine++;
  385. }
  386. /*
  387. * Skip past any white space preceeding the second token.
  388. */
  389. while (*lpszCommandLine && (*lpszCommandLine <= SPACECHAR)) {
  390. lpszCommandLine++;
  391. }
  392. StartupInfo.dwFlags = 0;
  393. GetStartupInfo( &StartupInfo );
  394. #ifdef WPRFLAG
  395. mainret = wWinMain(
  396. #else
  397. mainret = WinMain(
  398. #endif
  399. GetModuleHandleA(NULL),
  400. NULL,
  401. lpszCommandLine,
  402. StartupInfo.dwFlags & STARTF_USESHOWWINDOW
  403. ? StartupInfo.wShowWindow
  404. : SW_SHOWDEFAULT
  405. );
  406. #else /* _WINMAIN_ */
  407. #ifdef WPRFLAG
  408. __winitenv = envp;
  409. mainret = wmain(argc, argv, envp);
  410. #else
  411. __initenv = envp;
  412. mainret = main(argc, argv, envp);
  413. #endif
  414. #endif /* _WINMAIN_ */
  415. if ( !managedapp )
  416. exit(mainret);
  417. _cexit();
  418. }
  419. __except ( _XcptFilter(GetExceptionCode(), GetExceptionInformation()) )
  420. {
  421. /*
  422. * Should never reach here
  423. */
  424. mainret = GetExceptionCode();
  425. if ( !managedapp )
  426. _exit(mainret);
  427. _c_exit();
  428. } /* end of try - except */
  429. return mainret;
  430. }
  431. /***
  432. *check_managed_app() - Check for a managed executable
  433. *
  434. *Purpose:
  435. * Determine if the EXE the startup code is linked into is a managed app
  436. * by looking for the COM Runtime Descriptor in the Image Data Directory
  437. * of the PE or PE+ header.
  438. *
  439. *Entry:
  440. * None
  441. *
  442. *Exit:
  443. * 1 if managed app, 0 if not.
  444. *
  445. *Exceptions:
  446. *
  447. *******************************************************************************/
  448. static int __cdecl check_managed_app (
  449. void
  450. )
  451. {
  452. PIMAGE_DOS_HEADER pDOSHeader;
  453. PIMAGE_NT_HEADERS pPEHeader;
  454. PIMAGE_OPTIONAL_HEADER32 pNTHeader32;
  455. PIMAGE_OPTIONAL_HEADER64 pNTHeader64;
  456. pDOSHeader = (PIMAGE_DOS_HEADER)GetModuleHandleA(NULL);
  457. if ( pDOSHeader->e_magic != IMAGE_DOS_SIGNATURE )
  458. return 0;
  459. pPEHeader = (PIMAGE_NT_HEADERS)((char *)pDOSHeader +
  460. pDOSHeader->e_lfanew);
  461. if ( pPEHeader->Signature != IMAGE_NT_SIGNATURE )
  462. return 0;
  463. pNTHeader32 = (PIMAGE_OPTIONAL_HEADER32)&pPEHeader->OptionalHeader;
  464. switch ( pNTHeader32->Magic ) {
  465. case IMAGE_NT_OPTIONAL_HDR32_MAGIC:
  466. /* PE header */
  467. if ( pNTHeader32->NumberOfRvaAndSizes <=
  468. IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR )
  469. return 0;
  470. return !! pNTHeader32 ->
  471. DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR] .
  472. VirtualAddress;
  473. case IMAGE_NT_OPTIONAL_HDR64_MAGIC:
  474. /* PE+ header */
  475. pNTHeader64 = (PIMAGE_OPTIONAL_HEADER64)pNTHeader32;
  476. if ( pNTHeader64->NumberOfRvaAndSizes <=
  477. IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR )
  478. return 0;
  479. return !! pNTHeader64 ->
  480. DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR] .
  481. VirtualAddress;
  482. }
  483. /* Not PE or PE+, so not managed */
  484. return 0;
  485. }
  486. #endif /* CRTDLL */