回复 楼主 点线面
程序代码:
/***
*crtexe.c - Initialization for console EXE using CRT DLL
*
* Copyright (c) Microsoft Corporation. All rights reserved.
*
*Purpose:
* This is the actual startup routine for apps linking to the CRT DLL.
* It calls the user's main routine [w]main() or [w]WinMain after
* performing C Run-Time Library initialization.
*
* With ifdefs, this source file also provides the source code for:
* wcrtexe.c the startup routine for console apps with wide chars
* crtexew.c the startup routine for Windows apps
* wcrtexew.c the startup routine for Windows apps with wide chars
*
*******************************************************************************/
#ifdef CRTDLL
/*
* SPECIAL BUILD MACROS! 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.
* The symbol SPECIAL_CRTEXE is turned on to suppress the normal CRT DLL
* definition of _fmode and _commode using __declspec(dllexport). Otherwise
* this module would not be able to refer to both the local and DLL versions
* of these two variables.
*/
#undef CRTDLL
#ifndef _DLL
#define _DLL
#endif /* _DLL */
#define SPECIAL_CRTEXE
#include <cruntime.h>
#include <oscalls.h>
#include <internal.h>
#include <process.h>
#include <math.h>
#include <rterr.h>
#include <stdlib.h>
#include <tchar.h>
#include <rtcapi.h>
#include <sect_attribs.h>
#include <locale.h>
#ifdef _M_IA64
#pragma section(".base", long, read)
__declspec(allocate(".base"))
#endif /* _M_IA64 */
extern IMAGE_DOS_HEADER __ImageBase;
/*
* This has been moved from unhandld.cpp to here because, we only
* want to set the UnhandledExceptionFilter when this crt is loaded
* by an EXE (ie. not loaded by a DLL)
*/
int __cdecl __CxxSetUnhandledExceptionFilter(void);
_CRTALLOC(".CRT$XIY") static _PIFV pinit = &__CxxSetUnhandledExceptionFilter;
#define SPACECHAR _T(' ')
#define DQUOTECHAR _T('\"')
/* default floating point precision - X86 only! */
#ifdef _M_IX86
extern void _setdefaultprecision();
#endif /* _M_IX86 */
/*
* Declare function used to install a user-supplied _matherr routine.
*/
_CRTIMP void __setusermatherr( int (__cdecl *)(struct _exception *) );
/*
* Declare the names of the exports corresponding to _fmode and _commode
*/
#ifdef _M_IX86
#define _IMP___FMODE _imp___fmode
#define _IMP___COMMODE _imp___commode
#else /* _M_IX86 */
/* assumed to be IA64 or x64 */
#define _IMP___FMODE __imp__fmode
#define _IMP___COMMODE __imp__commode
#endif /* _M_IX86 */
extern int * _IMP___FMODE; /* exported from the CRT DLL */
extern int * _IMP___COMMODE; /* these names are implementation-specific */
extern int _fmode; /* must match the definition in <stdlib.h> */
extern int _commode; /* must match the definition in <internal.h> */
extern int _dowildcard; /* passed to __getmainargs() */
#ifdef _M_IX86
/*
* Declare/define communal to disable heap termination on corruption
*/
int _NoHeapEnableTerminationOnCorruption;
#endif /* _M_IX86 */
/*
* Declare/define communal that serves as indicator the default matherr
* routine is being used.
*/
int __defaultmatherr;
/*
* routine in DLL to do initialization (in this case, C++ constructors)
*/
extern int __cdecl _initterm_e(_PIFV *, _PIFV *);
extern void __cdecl _initterm(_PVFV *, _PVFV *);
/*
* routine to check if this is a managed application
*/
static int __cdecl check_managed_app(void);
/*
* pointers to initialization sections
*/
extern _CRTALLOC(".CRT$XIA") _PIFV __xi_a[];
extern _CRTALLOC(".CRT$XIZ") _PIFV __xi_z[]; /* C initializers */
extern _CRTALLOC(".CRT$XCA") _PVFV __xc_a[];
extern _CRTALLOC(".CRT$XCZ") _PVFV __xc_z[]; /* C++ initializers */
/*
* Pointer to callback function to initialize any dynamically initialized
* __declspec(thread) variables. This relies on a subtle aspect of C.
* The pointer is defined here uninitialized. It is defined initialized in
* tlsdyn.c. If user code uses dynamically initialized __declspec(thread)
* variables, then compiler-injected dependencies cause tlsdyn.obj to be
* linked. In that case, the non-zero definition of __dyn_tls_init_callback
* in tlsdyn.obj will take precedence, and the startup code will execute the
* callback. This use of multiple definitions is only legal in C, not C++.
*/
const PIMAGE_TLS_CALLBACK __dyn_tls_init_callback;
/*
* 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 set to -1 to
* mark this module as an EXE.
* NOTE - the pointers are stored encoded.
*/
extern _PVFV *__onexitbegin;
extern _PVFV *__onexitend;
/*
* All the below variables are made static global for this file. This facilitates
* in communicating mainCRTStartup and initialization code. Along with making these
* variables global, two new functions are created pre_c_init, pre_cpp_init. The functions
* are executed before anything in c_init and cpp_init sections repsectively.
*/
static int argc; /* three standard arguments to main */
static _TSCHAR **argv;
static _TSCHAR **envp;
static int argret;
static int mainret=0;
static int managedapp;
static int has_cctor = 0;
static _startupinfo startinfo;
static int __cdecl pre_c_init(void);
static void __cdecl pre_cpp_init(void);
_CRTALLOC(".CRT$XIAA") static _PIFV pcinit = pre_c_init;
_CRTALLOC(".CRT$XCAA") static _PVFV pcppinit = pre_cpp_init;
/***
*pre_c_init(void)
*
*Purpose:
* The code in mainCRTStartup that was executed before executing C
* initializers was shifted in this function. Also this funciton is the
* first thing that is executed in c init section.
*
*Entry:
*
*Exit:
*
*******************************************************************************/
static int __cdecl pre_c_init(void)
{
/*
* Determine if this is a managed application
*/
managedapp = check_managed_app();
/*
* Set __app_type properly
*/
#ifdef _WINMAIN_
__set_app_type(_GUI_APP);
#else /* _WINMAIN_ */
__set_app_type(_CONSOLE_APP);
#endif /* _WINMAIN_ */
/*
* Mark this module as an EXE file so that atexit/_onexit
* will do the right thing when called, including for C++
* d-tors.
*/
__onexitbegin = __onexitend = (_PVFV *) EncodePointer((_PVFV *)(-1));
/*
* Propogate the _fmode and _commode variables to the DLL
*/
*_IMP___FMODE = _fmode;
*_IMP___COMMODE = _commode;
/*
* Run the RTC initialization code for this DLL
*/
#ifdef _RTC
_RTC_Initialize();
#endif /* _RTC */
/*
* Call _setargv(), which will trigger a call to __setargv() if
* SETARGV.OBJ is linked with the EXE. If SETARGV.OBJ is not
* linked with the EXE, a dummy _setargv() will be called.
*/
#ifdef WPRFLAG
_wsetargv();
#else /* WPRFLAG */
_setargv();
#endif /* WPRFLAG */
/*
* If the user has supplied a _matherr routine then set
* __pusermatherr to point to it.
*/
if ( !__defaultmatherr )
__setusermatherr(_matherr);
#ifdef _M_IX86
_setdefaultprecision();
#endif /* _M_IX86 */
/* Enable per-thread locale if user asked for it */
if(__globallocalestatus == -1)
{
_configthreadlocale(-1);
}
return 0;
}
/***
*pre_cpp_init(void)
*
*Purpose:
* The code in mainCRTStartup that was executed after C initializers and
* before C++ initializers is shifted in this function. Also this funciton
* is the first thing that is executed in C++ init section.
*
*Entry:
*
*Exit:
*
*******************************************************************************/
static void __cdecl pre_cpp_init(void)
{
#ifdef _RTC
atexit(_RTC_Terminate);
#endif /* _RTC */
/*
* Get the arguments for the call to main. Note this must be
* done explicitly, rather than as part of the dll's
* initialization, to implement optional expansion of wild
* card chars in filename args
*/
startinfo.newmode = _newmode;
#ifdef WPRFLAG
argret = __wgetmainargs(&argc, &argv, &envp,
_dowildcard, &startinfo);
#else /* WPRFLAG */
argret = __getmainargs(&argc, &argv, &envp,
_dowildcard, &startinfo);
#endif /* WPRFLAG */
#ifndef _SYSCRT
if (argret < 0)
_amsg_exit(_RT_SPACEARG);
#endif /* _SYSCRT */
}
/***
*mainCRTStartup(void)
*wmainCRTStartup(void)
*WinMainCRTStartup(void)
*wWinMainCRTStartup(void)
*
*Purpose:
* These routines do the C runtime initialization, call the appropriate
* user entry function, and handle termination cleanup. For a managed
* app, they then return the exit code back to the calling routine, which
* is the managed startup code. For an unmanaged app, they call exit and
* never return.
*
* Function: User entry called:
* mainCRTStartup main
* wmainCRTStartup wmain
* WinMainCRTStartup WinMain
* wWinMainCRTStartup wWinMain
*
*Entry:
*
*Exit:
* Managed app: return value from main() et al, or the exception code if
* execution was terminated by the __except guarding the call
* to main().
* Unmanaged app: never return.
*
*******************************************************************************/
static
int
__tmainCRTStartup(
void
);
#ifdef _WINMAIN_
#ifdef WPRFLAG
int wWinMainCRTStartup(
#else /* WPRFLAG */
int WinMainCRTStartup(
#endif /* WPRFLAG */
#else /* _WINMAIN_ */
#ifdef WPRFLAG
int wmainCRTStartup(
#else /* WPRFLAG */
int mainCRTStartup(
#endif /* WPRFLAG */
#endif /* _WINMAIN_ */
void
)
{
/*
* The /GS security cookie must be initialized before any exception
* handling targetting the current image is registered. No function
* using exception handling can be called in the current image until
* after __security_init_cookie has been called.
*/
__security_init_cookie();
return __tmainCRTStartup();
}
__declspec(noinline)
int
__tmainCRTStartup(
void
)
{
#ifdef _WINMAIN_
_TUCHAR *lpszCommandLine;
STARTUPINFOW StartupInfo;
BOOL inDoubleQuote=FALSE;
GetStartupInfoW( &StartupInfo );
#endif /* _WINMAIN_ */
#ifdef _M_IX86
/*
* Enable app termination when heap corruption is detected on
* Windows Vista and above. This is a no-op on down-level OS's
* and enabled by default for 64-bit processes.
*/
if (!_NoHeapEnableTerminationOnCorruption)
{
HeapSetInformation(NULL, HeapEnableTerminationOnCorruption, NULL, 0);
}
#endif /* _M_IX86 */
/*
* Guard the initialization code and the call to user's main, or
* WinMain, function in a __try/__except statement.
*/
__try
{
/*
* There is a possiblity that the module where this object is
* linked into is a mixed module. In all the cases we gurantee that
* native initialization will occur before managed initialization.
* Also in anycase this code should never be called when some other
* code is initializing native code, that's why we exit in that case.
*
* Do runtime startup initializers.
*
* Note: the only possible entry we'll be executing here is for
* __lconv_init, pulled in from charmax.obj only if the EXE was
* compiled with -J. All other .CRT$XI* initializers are only
* run as part of the CRT itself, and so for the CRT DLL model
* are not found in the EXE. For that reason, we call _initterm,
* not _initterm_e, because __lconv_init will never return failure,
* and _initterm_e is not exported from the CRT DLL.
*
* Note further that, when using the CRT DLL, executing the
* .CRT$XI* initializers is only done for an EXE, not for a DLL
* using the CRT DLL. That is to make sure the -J setting for
* the EXE is not overriden by that of any DLL.
*/
void *lock_free=0;
void *fiberid=((PNT_TIB)NtCurrentTeb())->StackBase;
int nested=FALSE;
while((lock_free=InterlockedCompareExchangePointer((volatile PVOID *)&__native_startup_lock, fiberid, 0))!=0)
{
if(lock_free==fiberid)
{
nested=TRUE;
break;
}
/* some other thread is running native startup/shutdown during a cctor/domain unload.
Should only happen if this DLL was built using the Everett-compat loader lock fix in vcclrit.h
*/
/* wait for the other thread to complete init before we return */
Sleep(1000);
}
if (__native_startup_state == __initializing)
{
_amsg_exit( _RT_CRT_INIT_CONFLICT);
}
else if (__native_startup_state == __uninitialized)
{
__native_startup_state = __initializing;
#ifndef _SYSCRT
if (_initterm_e( __xi_a, __xi_z ) != 0)
{
return 255;
}
#else /* _SYSCRT */
_initterm((_PVFV *)(void *)__xi_a, (_PVFV *)(void *)__xi_z);
#endif /* _SYSCRT */
}
else
{
has_cctor = 1;
}
/*
* do C++ constructors (initializers) specific to this EXE
*/
if (__native_startup_state == __initializing)
{
_initterm( __xc_a, __xc_z );
__native_startup_state = __initialized;
}
_ASSERTE(__native_startup_state == __initialized);
if(!nested)
{
/* For X86, the definition of InterlockedExchangePointer wrongly causes warning C4312 */
#pragma warning(push)
#pragma warning(disable:4312)
InterlockedExchangePointer((volatile PVOID *)&__native_startup_lock, 0);
#pragma warning(pop)
}
/*
* If we have any dynamically initialized __declspec(thread)
* variables, then invoke their initialization for the primary
* thread used to start the process, by calling __dyn_tls_init
* through a callback defined in tlsdyn.obj.
*/
if (__dyn_tls_init_callback != NULL &&
_IsNonwritableInCurrentImage((PBYTE)&__dyn_tls_init_callback))
{
__dyn_tls_init_callback(NULL, DLL_THREAD_ATTACH, NULL);
}
/* Enable buffer count checking if linking against static lib */
_CrtSetCheckCount(TRUE);
#ifdef _WINMAIN_
/*
* Skip past program name (first token in command line).
* Check for and handle quoted program name.
*/
#ifdef WPRFLAG
lpszCommandLine = (wchar_t *)_wcmdln;
#else /* WPRFLAG */
lpszCommandLine = (unsigned char *)_acmdln;
#endif /* WPRFLAG */
while (*lpszCommandLine > SPACECHAR ||
(*lpszCommandLine&&inDoubleQuote)) {
/*
* Flip the count from 1 to 0 or 0 to 1 if current character
* is DOUBLEQUOTE
*/
if (*lpszCommandLine==DQUOTECHAR) inDoubleQuote=!inDoubleQuote;
#ifdef _MBCS
if (_ismbblead(*lpszCommandLine)) {
if (lpszCommandLine) {
lpszCommandLine++;
}
}
#endif /* _MBCS */
++lpszCommandLine;
}
/*
* Skip past any white space preceeding the second token.
*/
while (*lpszCommandLine && (*lpszCommandLine <= SPACECHAR)) {
lpszCommandLine++;
}
#ifdef WPRFLAG
mainret = wWinMain(
#else /* WPRFLAG */
mainret = WinMain(
#endif /* WPRFLAG */
(HINSTANCE)&__ImageBase,
NULL,
lpszCommandLine,
StartupInfo.dwFlags & STARTF_USESHOWWINDOW
? StartupInfo.wShowWindow
: SW_SHOWDEFAULT
);
#else /* _WINMAIN_ */
#ifdef WPRFLAG
__winitenv = envp;
mainret = wmain(argc, argv, envp);
#else /* WPRFLAG */
__initenv = envp;
mainret = main(argc, argv, envp);
#endif /* WPRFLAG */
#endif /* _WINMAIN_ */
/*
* Note that if the exe is managed app, we don't really need to
* call exit or _c_exit. .cctor should be able to take care of
* this.
*/
if ( !managedapp )
exit(mainret);
if (has_cctor == 0)
_cexit();
}
__except ( _XcptFilter(GetExceptionCode(), GetExceptionInformation()) )
{
/*
* Should never reach here
*/
mainret = GetExceptionCode();
/*
* Note that if the exe is managed app, we don't really need to
* call exit or _c_exit. .cctor should be able to take care of
* this.
*/
if ( !managedapp )
_exit(mainret);
if (has_cctor == 0)
_cexit();
} /* end of try - except */
return mainret;
}
/***
*check_managed_app() - Check for a managed executable
*
*Purpose:
* Determine if the EXE the startup code is linked into is a managed app
* by looking for the COM Runtime Descriptor in the Image Data Directory
* of the PE or PE+ header.
*
*Entry:
* None
*
*Exit:
* 1 if managed app, 0 if not.
*
*Exceptions:
*
*******************************************************************************/
static int __cdecl check_managed_app (
void
)
{
PIMAGE_DOS_HEADER pDOSHeader;
PIMAGE_NT_HEADERS pPEHeader;
pDOSHeader = &__ImageBase;
if (pDOSHeader->e_magic != IMAGE_DOS_SIGNATURE)
{
return 0;
}
pPEHeader = (PIMAGE_NT_HEADERS) ((BYTE *) pDOSHeader + pDOSHeader->e_lfanew);
if (pPEHeader->Signature != IMAGE_NT_SIGNATURE)
{
return 0;
}
if (pPEHeader->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR_MAGIC)
{
return 0;
}
/* prefast assumes we are overflowing __ImageBase */
#pragma warning(push)
#pragma warning(disable:26000)
if (pPEHeader->OptionalHeader.NumberOfRvaAndSizes <= IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR)
{
return 0;
}
#pragma warning(pop)
return pPEHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress != 0;
}
#endif /* CRTDLL */