你是否想过为什么有时候main()函数是入口地址,在win32中winmain()函数又是入口地址,其实是编译器在动态链接到crt[C runtime library(part of the C standard library)]时候设置的

程序设置断点,我们来看crtexe.c代码

第一个static int __cdecl pre_c_init(void)

*       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.

什么意思不用详细说,老外的注释很给力

static int __cdecl pre_c_init(void) {     /*      * Determine if this is a managed application      */     managedapp = check_managed_app();      /*      * Set __app_type properly      */ #ifdef _WINMAIN_    //根据WINMAIN宏来设置应用程序是GUI程序还是控制台程序     __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 *)_encode_pointer((_PVFV *)(-1));      /*      * Propogate the _fmode and _commode variables to the DLL      */     *_IMP___FMODE = _fmode;     *_IMP___COMMODE = _commode;  #ifdef _M_IX86     /*      * Set the local copy of the Pentium FDIV adjustment flag      */      _adjust_fdiv = * _imp___adjust_fdiv; #endif  /* _M_IX86 */      /*      * 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; }
这个函数在crt0dat.c中被调用,详细介绍,略去

第二个函数

static void __cdecl pre_cpp_init(void)
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 */ }

下面是程序的第一个入口处

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(); }
/***
*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
就是为程序找到入口地址,具体的判断是在函数
__tmainCRTStartup()中

关键代码:

#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_ */
我们看到,根据宏WPRFLAG来判断是wWinmain()还是WinMain(),根据_WINMAIN_来判断入口函数是main(),wmain()还是WinMain(),wWinMain()

wmain()和wWinMain()是unicode版的,main()和WinMain()是ANSI版的 不过在程序中始终没有找到宏WPRFLAG是在哪里定义的,有空了再详细研究

然后就找到对应的入口程序执行。