已有无数的书籍和网上的文章探讨过这个问题, 然而, 多数停留在这里:
CMyApp theApp;
theApp 是一个C++的全局对象, 因此会先于main函数运行.
_tWinMain 定义在 appmodul.cpp 中(不是少写了e, 微软为保证8.3文件名故意为之). 至此为止好像就皆大欢喜了.
extern "C" int WINAPI
_tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPTSTR lpCmdLine, int nCmdShow)
{
// call shared/exported WinMain
return AfxWinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow);
}
_tWinMain是一个宏, 视是否设置UNICODE宏而被替换为 wWinMain或WinMain
问题来了, 东西是找到了, 可是它怎么成为你的项目的一部分的? 毕竟appmodul.cpp 是藏在VC安装目录下的MFC源码(微软只提供MFC的部分源码)中, 难道是编译环境自动在编译时"插入"了这个源文件? 在网上搜索时的确找到这样想当然的说法, 编译环境不会这么做!
验证办法是: 生成一个MFC项目, build, 然后查看output窗口, 点击那个build的日志文件, 里面会有build过程的详细记录, 把这个记录中的命令COPY出来, 另存为一个.bat 文件, 运行这个.bat文件来生成最终的程序, 从这里你可以扔掉VC开发环境, 使得它不可能神秘地做一些你不知道的事情, 但是, 仅仅通过命令行来编译链接同样可以得到最终的可执行程序, 这说明并不是VC编译器所谓插入了对 appmodul.cpp的编译. 通过对每个命令的分析, cl和link命令行上也没有"神秘"的选项显示额外链接了什么文件.
那么appmodul.cpp的编译结果完全可以是预编译好的库被链接到最终可执行文件中的, 这个动作只能发生在link阶段, 那么link命令上又没有? 怎么回事?
原来是在afx.h 文件中, 通过#pragma comment(lib, "lib文件.lib")
这样的编译器扩展指示符实现的. 根据是否是UNICODE版本, 是否是DEBUG版本, 链入不同的静态MFC库文件, 其中u代表UNICODE, d代表DEBUG:
mfcs71u.lib
mfcs71.lib
mfcs71ud.lib
mfcs71d.lib
用strings (unix下的小程序, 可以通过cygwin或gnu win32这样的项目得到)或lib命令可以看到这些.
lib /LIST ..\atlmfc\lib\mfcs71.lib
Microsoft (R) Library Manager Version 7.10.3077
Copyright (C) Microsoft Corporation. All rights reserved.
INTEL\$DLL.W\stdafx.obj
INTEL\$DLL.W\nolib.obj
INTEL\$DLL.W\appmodul.obj
INTEL\$DLL.W\dllmodul.obj
INTEL\$DLL.W\oleexp.obj
INTEL\$DLL.W\dumpstak.obj
INTEL\$DLL.W\sockexp.obj
可以看到其中就有 appmodul.obj
用
lib mfcs71.lib /extract:INTEL\$DLL.W\appmodul.obj /out:tmp.obj
可以把它抽取出来. 再用反汇编工具分析, 因为这个函数只有一句话, 就是调用AfxWinMain函数, 所以用objdump反汇编的结果也很简单, 直接的一个跳转. 因为AfxWinMain是在dll中动态实现.
阅读(1643) | 评论(4) | 转发(0) |