main函数的前序执行过程简单介绍
main函数其实是我们能控制的程序入口,但是程序编译之后进行执行却不是从main函数开始的,这里主要讲解下VC6.0++下编译的程序在执行main函数之前的流程,其实主要为在执行main函数之前做了环境变量和参数个数以及参数的解析,然后初始化一些全局变量、堆、io等内容
/***
*crt0.c - C runtime initialization routine
*
* Copyright (c) 1989-1997, Microsoft Corporation. All rights reserved.
*
*Purpose:
* This the actual startup routine for apps. It calls the user's main
* routine [w]main() or [w]WinMain after performing C Run-Time Library
* initialization.
*
* (With ifdef's, this source file also provides the source code for
* wcrt0.c, the startup routine for console apps with wide characters,
* wincrt0.c, the startup routine for Windows apps, and wwincrt0.c,
* the startup routine for Windows apps with wide characters.)
*
*******************************************************************************/
#ifdef _WIN32
#ifndef CRTDLL
#include <cruntime.h>
#include <dos.h>
#include <internal.h>
#include <stdlib.h>
#include <string.h>
#include <rterr.h>
#include <windows.h>
#include <awint.h>
#include <tchar.h>
#include <dbgint.h>
/*
* wWinMain is not yet defined in winbase.h. When it is, this should be
* removed.
*/
int
WINAPI
wWinMain(
HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPWSTR lpCmdLine,
int nShowCmd
);
#ifdef WPRFLAG
_TUCHAR * __cdecl _wwincmdln(void);
#else /* WPRFLAG */
_TUCHAR * __cdecl _wincmdln(void);
#endif /* WPRFLAG */
/*
* command line, environment, and a few other globals
*/
#ifdef WPRFLAG
wchar_t *_wcmdln; /* points to wide command line */
#else /* WPRFLAG */
char *_acmdln; /* points to command line */
#endif /* WPRFLAG */
char *_aenvptr = NULL; /* points to environment block */
wchar_t *_wenvptr = NULL; /* points to wide environment block */
void (__cdecl * _aexit_rtn)(int) = _exit; /* RT message return procedure */
static void __cdecl fast_error_exit(int); /* Error exit via ExitProcess */
/*
* _error_mode and _apptype, together, determine how error messages are
* written out.
*/
int __error_mode = _OUT_TO_DEFAULT;
#ifdef _WINMAIN_
int __app_type = _GUI_APP;
#else /* _WINMAIN_ */
int __app_type = _CONSOLE_APP;
#endif /* _WINMAIN_ */
/***
*BaseProcessStartup(PVOID Peb)
*
*Purpose:
* This routine does the C runtime initialization, calls main(), and
* then exits. It never returns.
*
*Entry:
* PVOID Peb - pointer to Win32 Process Environment Block (not used)
*
*Exit:
* This function never returns.
*
*******************************************************************************/
#ifdef _WINMAIN_
#ifdef WPRFLAG
void wWinMainCRTStartup(
#else /* WPRFLAG */
//此处就是在main函数之前的入口
void WinMainCRTStartup(
#endif /* WPRFLAG */
#else /* _WINMAIN_ */
#ifdef WPRFLAG
void wmainCRTStartup(
#else /* WPRFLAG */
void mainCRTStartup(
#endif /* WPRFLAG */
#endif /* _WINMAIN_ */
void
)
{
int mainret;
#ifdef _WINMAIN_
_TUCHAR *lpszCommandLine;
STARTUPINFO StartupInfo;
#endif /* _WINMAIN_ */
/*
* Get the full Win32 version
*/
//首先获取操作系统的版本信息
_osver = GetVersion();
//内部的版本号这边是采取位运算来得到的
_winminor = (_osver >> 8) & 0x00FF ;
_winmajor = _osver & 0x00FF ;
_winver = (_winmajor << 8) + _winminor;
_osver = (_osver >> 16) & 0x00FFFF ;
#ifdef _MT
//初始化堆环境
if ( !_heap_init(1) ) /* initialize heap */
#else /* _MT */
if ( !_heap_init(0) ) /* initialize heap */
#endif /* _MT */
fast_error_exit(_RT_HEAPINIT); /* write message and die */
#ifdef _MT
//如果支持多线程就初始化多线程的环境
if( !_mtinit() ) /* initialize multi-thread */
fast_error_exit(_RT_THREAD); /* write message and die */
#endif /* _MT */
/*
* Guard the remainder of the initialization code and the call
* to user's main, or WinMain, function in a __try/__except
* statement.
*/
__try {
//初始化IO
_ioinit(); /* initialize lowio */
#ifdef WPRFLAG
/* get wide cmd line info */
//这里就是取得命令行,这里是宽字节版本
_wcmdln = (wchar_t *)__crtGetCommandLineW();
/* get wide environ info */
//这边取得环境变量,取得变量是以空格分开的
_wenvptr = (wchar_t *)__crtGetEnvironmentStringsW();
//此处就是初始化main函数的argv参数
_wsetargv();
//此处进行环境变量的设置
_wsetenvp();
#else /* WPRFLAG */
//这边就是非宽字节版本的处理流程
/* get cmd line info */
_acmdln = (char *)GetCommandLineA();
/* get environ info */
_aenvptr = (char *)__crtGetEnvironmentStringsA();
_setargv();
_setenvp();
#endif /* WPRFLAG */
//此处就是进行初始化浮点寄存器,初始化标准库需要支持的全局对象和用户自定义的对象
_cinit(); /* do C data initialize */
//根据WINMAIN宏来设置应用程序是GUI程序还是控制台程序
#ifdef _WINMAIN_
StartupInfo.dwFlags = 0;
//获取进程的启动状态
GetStartupInfo( &StartupInfo );
#ifdef WPRFLAG
//这里还是根据宽字节是Unicode版本还是非Unicode版本进行处理
lpszCommandLine = _wwincmdln();
mainret = wWinMain(
#else /* WPRFLAG */
lpszCommandLine = _wincmdln();
mainret = WinMain(
#endif /* WPRFLAG */
GetModuleHandleA(NULL),
NULL,
lpszCommandLine,
StartupInfo.dwFlags & STARTF_USESHOWWINDOW
? StartupInfo.wShowWindow
: SW_SHOWDEFAULT
);
#else /* _WINMAIN_ */
#ifdef WPRFLAG
//这里是根据是否是控制台程序来进行调用main函数
__winitenv = _wenviron;
mainret = wmain(__argc, __wargv, _wenviron);
#else /* WPRFLAG */
__initenv = _environ;
mainret = main(__argc, __argv, _environ);
#endif /* WPRFLAG */
#endif /* _WINMAIN_ */
//此处进行退出main函数
exit(mainret);
}
//此处使用了windows的异常处理机制(SEH),而过滤函数_XcptFilter 首先会检查设置了异常处理函数,如果用户设置了异常处理,就首先会调用用户设置的异常处理函数
//GetExceptionCode 返回发生的异常的标识
//每一个SEH异常都有一个与其相关联的异常码(exception code)。你可以使用GetExceptionCode()函数来获取异常码。你可以通过GetExceptionInformation()来获取异常信息
__except ( _XcptFilter(GetExceptionCode(), GetExceptionInformation()) )
{
/*
* Should never reach here
*/
//退出
_exit( GetExceptionCode() );
} /* end of try - except */
}
关于_XcptFilter函数其实就是识别异常并采取相关操作
int __cdecl _XcptFilter(
unsigned long xcptnum,
PEXCEPTION_POINTERS pxcptinfoptrs
);
[in] xcptnum
异常标识符。
[in] pxcptinfoptrs
指向异常信息的指针。