1 最近在做ATL, 始终不能理解ATL的实质, 掌握不了它的基本原理. 因为自己"掌握"了MFC, 它们同样是一套类库, 而MFC不但是一套类库, 更是一套Application Framework. 所以觉得理解ATL不应该是问题. 但是最后不但没有理解ATL, 反而发现自己根本就没有"掌握"MFC.
比如MFC 与 windows sdk 之间的关系, 我只知道mfc包装了sdk, 但是究竟是怎么包装的,我根本不明白, 这也就是我不明白CWnd::FromHandle()的原因. 为什么这么多年来始终没有学习到这些东西呢? 从来没有认真的读过MSDN中的CWND的说明!
ATL是一组类, 要看一下它是如何包装的sdk, 与MFC有何不同, 为什么ATL在操作窗口类的时候要用fromhandle转换一下.?
理解MFC与ATL: 我们先来看windows sdk: 在windows sdk中, 我们这样创建窗口: HWND hwnd; // Save the application-instance handle. // Create the main window. hwnd = CreateWindow( "MainWClass", // name of window class "Sample", // title-bar string WS_OVERLAPPEDWINDOW, // top-level window CW_USEDEFAULT, // default horizontal position CW_USEDEFAULT, // default vertical position CW_USEDEFAULT, // default width CW_USEDEFAULT, // default height (HWND) NULL, // no owner window (HMENU) NULL, // use class menu hinstance, // handle to application instance (LPVOID) NULL); // no window-creation data if (!hwnd) return FALSE; 若干年前,windows的程序员们都是用这样的函数来写代码。 但是人们发现这样很麻烦。。。在C++被发明以后, 微软公司的程序员们想到这样一个办法, 创建一个类, 用它来把关于windows窗口的函数包装起来,这样其它人就很方便的写出创建和管理窗口方面的代码了。 这个类就叫做CWnd. 我们使用CWnd类的Create()函数来创建窗口,其实Create()内部是调用了windows sdk CreateWindow()函数的, 在Cwnd中有个HWND m_hWnd, 它里面保存CreateWindow()返回的hwnd. CWnd 又提供了其它的许多成员函数,通过它们来操作这个窗口(这些成员函数内部分别调用吧各种各样的windows sdk, 这些sdk需要的HWND参数可以从它的成员m_hWnd看获得)。 我们把这样的一套类称为MFC. 后来出现了COM技术, 一开始程序员们用comsdk来编写COM组件,comsdk同windows sdk一样不方便, 所以微软又开发吧ATL类库。为了理解ATL与MFC的不同, 我们抛开其它的类不管,专门看ATL中关于窗口的类,在ATL中, 包装窗口的类叫做CWindow. 同MFC的CWnd一样,它也有一个HWND m_hWnd,也有一个Create()函数,这两个Create()的一个重要区别是,在指定父窗口时,MFC的Create()的参数类型是CWnd*, 而ATL的Create()的参数类型是HWND. 虽然他们包装的方法上略有不同,但是它们包装的是同一个东西:windows window. 他们底层都是调用相同的windows sdk去操作一个用hwnd标识的窗口。所以理论上他们两个可以互相调用。 在一个ATL工程中,你可以声明一个MFC类的对象(因为MFC类也就是一个C++类。我们可以编写一个实现特定功能的类,然后给这些类起个名字)。 我们可以调用它的成员函数(因为MFC和ATL都是调用一样的底层windows sdk去操作由m_hWnd指定的窗口)。所以由此看来,对于windows窗口,我们可以混合使用ATL和MFC来对同一个窗口操作。唯一需要注意的是,MFC中CWnd的函数使用的是CWnd*参数, 而ATL中CWindow的函数使用的是HWND参数。所以我们需要在他们之间进行转换。从HWND转向CWnd*使用CWnd::FromHandle(HWND), 编译器可以根据hwnd来创建出一个CWnd来(它知道Cwnd的内存结构,而这个内存结构只和HWND有关,所以编译器有足够的信息创建出CWnd来)。 所以,MFC和ATL是两套不同的类库,但是它们包装的都是windows sdk. 只是包装的方法不同。 QA: 1 在ATL工程中是否可以使用MFC类?可以。 2 既然MFC中已经有了关于窗口的类,而且ATL中又可以使用MFC,那为什么ATL要单独开发自己的类Cwindow呢? 如果ATL使用MFC中的CWnd,那么这个程序就要依赖MFC运行时库。效率很低。 3 m_caseReport是一个MFC类对象, 为什么在MFC工程中,在 void CBrResourceMgr::createCaseListWindow() { if (!m_caseReport.Create(dwWndStyle, rtList, this, IDC_CASE_GRID))可以, } 但是在ATL中要 void CBrResourceMgrImpl::createCaseListWindow() { CWnd *pWnd = CWnd::FromHandle(m_hWnd); if (!m_caseReport.Create(dwWndStyle, rtList, pWnd, IDC_CASE_GRID)) } 因为MFC中的CBrResourceMgr是派生自CWnd, 所以create中的this本身就是CWnd*类型的。 但是ATL中的CBrResourceMgrImpl却是CWindow派生类,不能赋给CWnd.