__try {
_ioinit(); /* initialize lowio */
_acmdln = (char *)GetCommandLineA(); /* get cmd line info */
_aenvptr = (char *)__crtGetEnvironmentStringsA(); /* get environ info */
_setargv();
_setenvp();
__initenv = _environ;
mainret = main(__argc, __argv, _environ);
exit(mainret);
}
__except ( _XcptFilter(GetExceptionCode(), GetExceptionInformation()) )
{
_exit( GetExceptionCode() ); /* Should never reach here */
} /* end of try - except */
} 如果使用MFC框架,WinMain也会被埋藏在MFC库中(APPMODUL.CPP):
extern "C" int WINAPI
_tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPTSTR lpCmdLine, int nCmdShow)
{
// call shared/exported WinMain
return AfxWinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow);
}
对于ANSI版本,"_tWinMain"就是"WinMain";对于UINCODE版本,"_tWinMain"就是"wWinMain"。可参见afx.h:
#ifdef _UNICODE
#define _tmain wmain
#define _tWinMain wWinMain
#else
#define _tmain main
#define _tWinMain WinMain
#endif
全局C++对象的构造函数是在什么地方调用的?答案是在进入应用程序的Entry Point后,提示在调用main函数前的初始化操作中。所以MFC的theApp的构造函数是在_tWinMain之前调用的。
4、不显示Console窗口的Console程序
在默认情况下/subsystem 和/entry开关是匹配的,也就是:
"console"对应"mainCRTStartup"或者"wmainCRTStartup"
"windows"对应"WinMain"或者"wWinMain"
我们可以通过手动修改的方法使他们不匹配。例如:
#include "windows.h"
#pragma comment( linker, "/subsystem:\"windows\" /entry:\"mainCRTStartup\"" ) // 设置入口地址
void main(void)
{
MessageBox(NULL, "hello", "Notice", MB_OK);
}
这个Console程序就不会显示Console窗口。如果选/MLd的话,这个程序只需要链接LIBCD.LIB user32.lib kernel32.lib。
其实如果不想看到Console窗口,还有一个更直接的方法:那就是直接在EXE文件中将PE文件头的Subsystem从3改成2。在EXE文件中,PE文件头的偏移地址是0x3c,Subsystem是一个WORD,它在PE文件头中的偏移是0x5c。
5、MFC的库文件
MFC的库可以静态链接,也可以动态链接。静态库和动态库又有Debug和Release,ANSI和Unicode版本之分。
静态MFC库主要有:
ANSI Debug NAFXCWD.LIB
ANSI Release NAFXCW.LIB
Unicode Debug UAFXCWD.LIB
Unicode Release UAFXCW.LIB
动态链接库主要有;
ANSI Debug MFCxxD.LIB (core,MFCxxD.DLL),
MFCOxxD.LIB (OLE,MFCOxxD.DLL),
MFCDxxD.LIB (database,MFCDxxD.DLL),
MFCNxxD.LIB (network,MFCNxxD.DLL),
MFCSxxD.LIB (static)
ANSI Release MFCxx.LIB (combined,MFCxx.DLL)
MFCSxx.LIB (static)
Unicode Debug MFCxxUD.LIB (core,MFCxxUD.DLL),
MFCOxxUD.LIB (OLE,MFCOxxUD.DLL),
MFCDxxUD.LIB (database,MFCDxxUD.DLL),
MFCNxxUD.LIB (network,MFCNxxUD.DLL),
MFCSxxUD.LIB (static)
Unicode Release MFCxxU.DLL (combined,MFCxxU.DLL),
MFCSxxU.LIB (static)
上面的LIB文件除了MFCSxx(D、U、UD).LIB以外都是导入库。
MFC动态链接库版本也需要静态链接一些文件,这些文件就放在MFCSxx(D、U、UD).LIB中。例如包含_tWinMain的appmodul.cpp。
6、结束语
研究这些问题的动机是想弄清楚我们的程序是如何装载、运行的。但是,由于Windows不是开源平台,提示只能研究到PE文件(Windows上可执行文件的格式)。entry point、subsystem都是PE文件头的一部分。
Windows在进入PE文件的entry point之前做了些什么,就看不到了,只能概推测:应该是创建一个进程,装载PE文件和所有需要的DLL,初始化C变量,然后从某个起点函数开始运行。不同的subsystem,应该有不同的起点。调用这个起点函数时应该传入PE文件的entry point地址。