鱼C论坛

 找回密码
 立即注册
查看: 8057|回复: 36

MFC是怎样封装API函数的

[复制链接]
发表于 2013-11-19 22:12:00 | 显示全部楼层 |阅读模式
50鱼币
请用浅显易懂的方式说下MFC是怎样封装窗口和消息的。多一些注释,附图就更好了。

最佳答案

查看完整内容

认真看windows程序设计5,认真看这一本书抵得上其它的10本书。用SDK写界面不难,你觉得难的话,去看MFC肯定觉得更难。只要看明白了,一般的小问题就能自己解决了,至于示例,相信此书上的实例你还有很多没搞明白,不然怎么会觉得SDK写很难呢? MFC写小程序开发速度不一定比得上SDK,灵活性显然更差。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2013-11-19 22:12:01 | 显示全部楼层

认真看windows程序设计5,认真看这一本书抵得上其它的10本书。用SDK写界面不难,你觉得难的话,去看MFC肯定觉得更难。只要看明白了,一般的小问题就能自己解决了,至于示例,相信此书上的实例你还有很多没搞明白,不然怎么会觉得SDK写很难呢?
MFC写小程序开发速度不一定比得上SDK,灵活性显然更差。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2013-11-21 15:01:51 | 显示全部楼层
http://pan.baidu.com/share/link?shareid=1898614691&uk=1513950714   深入浅出mfc
建议看下这本书吧,是讲mfc的经典。
http://pan.baidu.com/share/link?shareid=1918448307&uk=1513950714  windows程序设计
如果看不懂建议先看windows程序设计。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2013-11-22 09:06:53 | 显示全部楼层
窗口的封装
mfc底层有个窗口基类叫CWnd, 前台见到的窗口都是继承与他, 这个类的模型简单点可以如下表示
class CWnd
{
public
        BOOL CreateEx(......);    //具体参数参考windowsapi   CreateEX
        void ShowWindows(int sw_cmdLine);    //具体参考CWnd::ShowWindows
        void UpdateWindows();     //更新窗口
private:
        HWnd  m_hWnd;   //窗口句柄
}
所以这类更像是一个带有窗口句柄的管理类.  
特别注意!!! 哪怕内部m_hwnd的窗口销毁了。 该类对象还是存在的.

窗口消息处理
简单的windows消息是如下伪代码表示
while(&msg)
{
case WM_KEYDOWN:
        dosomething;
case WM_CREATE
        dosomethin;
        ......
}
但是如果mfc也类似写的话。那么Cwnd类要写一堆的虚函数,来对应每个消息的处理。
这个显然不科学。所以mfc有自己的一套消息机制,

原理: mfc会在启动之后,在进程中建立类名和句柄的映射关系,假如前台在a界面上点击了左键
那么会发送消息体, 里面句柄是a的句柄, 这个时候mfc会根据句柄找到消息a的类, 然后在a.h和a.cpp中
查看
DECLARE_MESSAGE_MAP()段

BEGIN_MESSAGE_MAP(CADlg, CDialogEx)
END_MESSAGE_MAP()

是否有该消息的处理时间,如果有,则按事件处理,否则按默认的处理.
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2013-11-22 13:03:23 | 显示全部楼层
- -~ 都是大神.我楼上的太猛了....我还么入门呢!~:shock:
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2013-11-22 21:12:58 | 显示全部楼层
风のQ 发表于 2013-11-22 09:06
窗口的封装
mfc底层有个窗口基类叫CWnd, 前台见到的窗口都是继承与他, 这个类的模型简单点可以如下表示
...

呵呵,对于MFC刚产生时期的电脑来说,速度非常慢,所以将消息处理实现为虚函数会导致处理速度严重下降。但是,现在计算机速度快了,经得起这一点的性能损耗,所以反而显得MFC的做法不合时宜了。
诸如:
DECLARE_MESSAGE_MAP()段

BEGIN_MESSAGE_MAP(CADlg, CDialogEx)
END_MESSAGE_MAP()
这些宏,是非常招人讨厌的。因为这不是C++语言,利用宏来搞一套自己的语言有意思么?有意思的话还不如不用C++来完成那个这个任务,刚崔换种语言不是更好么?
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2013-11-22 21:52:40 | 显示全部楼层
仰望天上的光 发表于 2013-11-22 21:12
呵呵,对于MFC刚产生时期的电脑来说,速度非常慢,所以将消息处理实现为虚函数会导致处理速度严重下降。但 ...

也许有这些原因在里面, 到那时不得不说,他的这套框架式属于扩展性较好的,假如后期新增了windows消息,他不用改动这套框架,假如是每个消息对应虚函数。则需要新增消息应对函数,这在代码后期维护上还是有点麻烦的。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2013-11-22 23:48:08 | 显示全部楼层
风のQ 发表于 2013-11-22 21:52
也许有这些原因在里面, 到那时不得不说,他的这套框架式属于扩展性较好的,假如后期新增了windows消息, ...

不用改?不增加windows消息,MFC只要处理任何消息都要改。比如在
BEGIN_MESSAGE_MAP(CADlg, CDialogEx)
END_MESSAGE_MAP()之间写一堆的Onxxx这些就是对程序的修改,只不过是利用宏的特性使得这些修改看起来很小而已。
事实上,MFC废弃C++的虚拟函数表不用,自己在很多类里添加消息转发功能(其实就是添加static 元素取代原来的C++虚函数表),并以几个宏维护这些功能,这本身就像是在自己创建一个新的语言。既然要花如此大的代价来实现这样的功能,只能说明,C++语言不适合MFC的这种框架。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2013-11-23 10:14:58 | 显示全部楼层
去看windowsAPI接口,函数,编程实例,其实就是把API封装进类里面
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2013-11-23 10:15:49 | 显示全部楼层
把鼠标移到代码上按F12多看看是怎么封装的
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2013-11-23 21:23:25 | 显示全部楼层
我有一个分析MFC的源码的教程然后自己实现的教程 你加我发给你
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2013-11-23 22:49:56 | 显示全部楼层
本帖最后由 拈花小仙 于 2013-11-26 13:13 编辑
杞人 发表于 2013-11-23 21:23
我有一个分析MFC的源码的教程然后自己实现的教程 你加我发给你

加QQ吗?小金鱼的我看过,看不懂
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2013-11-23 22:54:08 | 显示全部楼层
windows 程序设计
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2013-11-26 08:31:13 | 显示全部楼层
仰望天上的光 发表于 2013-11-22 23:48
不用改?不增加windows消息,MFC只要处理任何消息都要改。比如在
BEGIN_MESSAGE_MAP(CADlg, CDialogEx)
...

你这样说也对。只能说我们能看到的问题,微软肯定也能看到,但是到了vs2010还是那套框架。总归是有他的道理的。也许我还认识不到位吧。。。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2013-11-26 08:32:39 | 显示全部楼层
没加好友权限。不好意思了。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2013-11-26 08:47:34 | 显示全部楼层
你对类和类的三态熟悉程度怎么样?
我觉得mfc已经是对类的三态运用的很经典的例子了。

要熟悉mfc先从学习类和类的三态开始, 在这之后你再去看一些大神的教学讲解视频比较好.
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2013-11-26 13:14:46 | 显示全部楼层
风のQ 发表于 2013-11-26 08:47
你对类和类的三态熟悉程度怎么样?
我觉得mfc已经是对类的三态运用的很经典的例子了。

封装 继承 多态吗?还是不懂怎么封装的
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2013-11-26 13:50:25 | 显示全部楼层
拈花小仙 发表于 2013-11-26 13:14
封装 继承 多态吗?还是不懂怎么封装的

额。所有想到出来的dlg或者view或者啥的都是继承自CWnd的,CWnd只是放了接口供你实现自己的事情而已,
要不你在把问题具体点。。。是指窗口类的内部结构,比如成员变量或函数什么的? 还是一个窗口的初始化过程?。。。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2013-11-26 13:52:34 | 显示全部楼层
风のQ 发表于 2013-11-26 13:50
额。所有想到出来的dlg或者view或者啥的都是继承自CWnd的,CWnd只是放了接口供你实现自己的事情而已,
要 ...

嗯嗯,想知道内部怎么初始化的,消息怎么映射的,最好把主要代码拿出来,多一些注释
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2013-11-26 14:31:16 | 显示全部楼层
拈花小仙 发表于 2013-11-26 13:52
嗯嗯,想知道内部怎么初始化的,消息怎么映射的,最好把主要代码拿出来,多一些注释

// 类声明, 自建一个窗口类并让这个窗口显示.
class CMyFrame : public CWnd
{
        DECLARE_DYNAMIC(CMyFrame )
public:
        CMyFrame ();
        virtual ~CMyFrame ();
protected:
        DECLARE_MESSAGE_MAP()
        afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);   
private:
       //此处放一些自己要在窗口上放的元素, 比如button声明的
};

int CMyFrame ::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
        //下面是根据继承原理, 构造子类前,先构造父类
        if (CWnd::OnCreate(lpCreateStruct) == -1)
                return -1;
        //此处是自己创建的窗口的私有元素的初始化
        //TODO
        return 0;
}

//调用生成代码。在App实例类中进行
CMyFrame * pFrame = new CMyFrame ();        
// 上句生成自己的窗口对象(严格说是管理类), 此时对象中的m_hwnd句柄为空,但是可以初始化自己的变量
也就是调用类中的Create函数
pFrame->CreateEx(0,  
                _T("CFRAME"),
                _T("Test"),               
                WS_POPUPWINDOW | WS_MAXIMIZEBOX | WS_MINIMIZEBOX | WS_THICKFRAME ,
                0,0,100,100,NULL,NULL
                );
//上句开始做初始化过程.CreateEx为子类CWnd拥有, 所以开始调用CWnd的CreateEx函数
//一下代码在Wincore.cpp中。c++目录下自己找找
        BOOL CWnd::CreateEx(DWORD dwExStyle, LPCTSTR lpszClassName,LPCTSTR lpszWindowName, DWORD dwStyle,
                int x, int y, int nWidth, int nHeight,
                HWND hWndParent, HMENU nIDorHMenu, LPVOID lpParam)
        {
                ASSERT(lpszClassName == NULL || AfxIsValidString(lpszClassName) ||
                        AfxIsValidAtom(lpszClassName));
                ENSURE_ARG(lpszWindowName == NULL || AfxIsValidString(lpszWindowName));
       
                // allow modification of several common create parameters
                CREATESTRUCT cs;
                cs.dwExStyle = dwExStyle;
                cs.lpszClass = lpszClassName;
                cs.lpszName = lpszWindowName;
                cs.style = dwStyle;
                cs.x = x;
                cs.y = y;
                cs.cx = nWidth;
                cs.cy = nHeight;
                cs.hwndParent = hWndParent;
                cs.hMenu = nIDorHMenu;
                cs.hInstance = AfxGetInstanceHandle();
                cs.lpCreateParams = lpParam;
                if (!PreCreateWindow(cs))    //注意这个函数,就是我们可以实现的虚函数,可以干一些创建之前要干的事情,比如自己注册窗口.
                {
                        PostNcDestroy();
                        return FALSE;
                }
                AfxHookWindowCreate(this);
                HWND hWnd = ::AfxCtxCreateWindowEx(cs.dwExStyle, cs.lpszClass,                        //此处创建窗口.
                                cs.lpszName, cs.style, cs.x, cs.y, cs.cx, cs.cy,
                                cs.hwndParent, cs.hMenu, cs.hInstance, cs.lpCreateParams);、
                。。。略。
        }               
pFrame->ShowWindow(SW_SHOW);   //显示自己的窗口
pFrame->UpdateWindow();   //更新自己的窗口.





想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-11-22 21:43

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表