拈花小仙 发表于 2013-11-19 22:12:00

MFC是怎样封装API函数的

请用浅显易懂的方式说下MFC是怎样封装窗口和消息的。多一些注释,附图就更好了。

仰望天上的光 发表于 2013-11-19 22:12:01

拈花小仙 发表于 2013-11-28 02:29 static/image/common/back.gif
想通过学习MFC,做了实例,了解SDK中到底有多少库函数,看他们是怎么应用的,也有助于SDK编程吧?我不懂, ...

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

peterboboo 发表于 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=1513950714windows程序设计
如果看不懂建议先看windows程序设计。

风のQ 发表于 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:
        HWndm_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()

是否有该消息的处理时间,如果有,则按事件处理,否则按默认的处理.

ヽ朝暮是安然 发表于 2013-11-22 13:03:23

- -~ 都是大神.我楼上的太猛了....我还么入门呢!~:shock:

仰望天上的光 发表于 2013-11-22 21:12:58

风のQ 发表于 2013-11-22 09:06 static/image/common/back.gif
窗口的封装
mfc底层有个窗口基类叫CWnd, 前台见到的窗口都是继承与他, 这个类的模型简单点可以如下表示
...

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

BEGIN_MESSAGE_MAP(CADlg, CDialogEx)
END_MESSAGE_MAP()
这些宏,是非常招人讨厌的。因为这不是C++语言,利用宏来搞一套自己的语言有意思么?有意思的话还不如不用C++来完成那个这个任务,刚崔换种语言不是更好么?

风のQ 发表于 2013-11-22 21:52:40

仰望天上的光 发表于 2013-11-22 21:12 static/image/common/back.gif
呵呵,对于MFC刚产生时期的电脑来说,速度非常慢,所以将消息处理实现为虚函数会导致处理速度严重下降。但 ...

也许有这些原因在里面, 到那时不得不说,他的这套框架式属于扩展性较好的,假如后期新增了windows消息,他不用改动这套框架,假如是每个消息对应虚函数。则需要新增消息应对函数,这在代码后期维护上还是有点麻烦的。

仰望天上的光 发表于 2013-11-22 23:48:08

风のQ 发表于 2013-11-22 21:52 static/image/common/back.gif
也许有这些原因在里面, 到那时不得不说,他的这套框架式属于扩展性较好的,假如后期新增了windows消息, ...

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

初海丶介 发表于 2013-11-23 10:14:58

去看windowsAPI接口,函数,编程实例,其实就是把API封装进类里面

初海丶介 发表于 2013-11-23 10:15:49

把鼠标移到代码上按F12多看看是怎么封装的

杞人 发表于 2013-11-23 21:23:25

我有一个分析MFC的源码的教程然后自己实现的教程 你加我发给你

拈花小仙 发表于 2013-11-23 22:49:56

本帖最后由 拈花小仙 于 2013-11-26 13:13 编辑

杞人 发表于 2013-11-23 21:23 static/image/common/back.gif
我有一个分析MFC的源码的教程然后自己实现的教程 你加我发给你
加QQ吗?小金鱼的我看过,看不懂

lovebite 发表于 2013-11-23 22:54:08

windows 程序设计

风のQ 发表于 2013-11-26 08:31:13

仰望天上的光 发表于 2013-11-22 23:48 static/image/common/back.gif
不用改?不增加windows消息,MFC只要处理任何消息都要改。比如在
BEGIN_MESSAGE_MAP(CADlg, CDialogEx)
...

你这样说也对。只能说我们能看到的问题,微软肯定也能看到,但是到了vs2010还是那套框架。总归是有他的道理的。也许我还认识不到位吧。。。

风のQ 发表于 2013-11-26 08:32:39

没加好友权限。不好意思了。

风のQ 发表于 2013-11-26 08:47:34

你对类和类的三态熟悉程度怎么样?
我觉得mfc已经是对类的三态运用的很经典的例子了。

要熟悉mfc先从学习类和类的三态开始, 在这之后你再去看一些大神的教学讲解视频比较好.

拈花小仙 发表于 2013-11-26 13:14:46

风のQ 发表于 2013-11-26 08:47 static/image/common/back.gif
你对类和类的三态熟悉程度怎么样?
我觉得mfc已经是对类的三态运用的很经典的例子了。



封装 继承 多态吗?还是不懂怎么封装的

风のQ 发表于 2013-11-26 13:50:25

拈花小仙 发表于 2013-11-26 13:14 static/image/common/back.gif
封装 继承 多态吗?还是不懂怎么封装的

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

拈花小仙 发表于 2013-11-26 13:52:34

风のQ 发表于 2013-11-26 13:50 static/image/common/back.gif
额。所有想到出来的dlg或者view或者啥的都是继承自CWnd的,CWnd只是放了接口供你实现自己的事情而已,
要 ...

嗯嗯,想知道内部怎么初始化的,消息怎么映射的,最好把主要代码拿出来,多一些注释

风のQ 发表于 2013-11-26 14:31:16

拈花小仙 发表于 2013-11-26 13:52 static/image/common/back.gif
嗯嗯,想知道内部怎么初始化的,消息怎么映射的,最好把主要代码拿出来,多一些注释

// 类声明, 自建一个窗口类并让这个窗口显示.
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();   //更新自己的窗口.





页: [1] 2
查看完整版本: MFC是怎样封装API函数的