__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地址。