孙鑫vc学习笔记:第三讲-尊龙官方平台

孙鑫vc学习笔记:第三讲

el/2024/3/25 15:53:45

第三讲2个半小时,听得好累啊!

在网上找到了别人做得笔记,非常好,于是拿过来用,在他的基础上增加一些内容。
不然全部自己写的话,估计写不到他那么好!

 


 

在mfc生成的应用程序口,窗口的生成跟第一讲不太一样,是怎样生成的?
1,寻找winmain入口:(mfc向导生成的程序找不到winmain函数,它是在编译的时候由链接器链接到程序当中的)
在安装目录下找到mfc文件夹下的src文件夹,src下是mfc源代码。
路径:mfc/src/appmodul.cpp:
_twinmain(hinstance hinstance, hinstance hprevinstance,
 //_twinmain其实是一个宏 #define _twinmain  winmain
 lptstr lpcmdline, int ncmdshow)
{
 // call shared/exported winmain
 return afxwinmain(hinstance, hprevinstance, lpcmdline, ncmdshow);
}
注意:(#define _twinmain   winmain)

2,c 中,全局对象的构造函数在main()开始执行之前被调用,全局对象被创建。全局构造函数按照它们在同一个文件中的声明顺序被调用。全局函数析构函数在main()函数结束后按照相反的顺序被调用。同样地,在vc 中,全局对象或全局变量来,在程序运行即winmain函数加载的时候,已经为全局对象或全局变量分配了内存和赋初值。
所以:cteapp theapp;->cteapp ::cteapp(){}->_twinmain(){}

说明:每一个mfc程序,有且只有一个从winapp类派生的类(应用程序类),也只有一个从应用程序类所事例化的对象,表示应用程序本身。在win32程序当中,表示应用程序是通过winmain入口函数来表示的(通过一个应用程序的一个事例号这一个标识来表示的)。在基于mfc应用程序中,是通过产生一个应用程序对象,用它来唯一的表示了应用程序。

3,通过构造应用程序对象过程中调用基类cwinapp的构造函数,在cwinapp的构造函数中对程序包括运行时一些初始化工作完成了。[派生类构造之前先构造基类]
cwinapp构造函数:mfc|src|appcore.cpp
cwinapp::cwinapp(lpctstr lpszappname){...}//带参数,而cteapp构造函数
 //没有显式向父类传参,难道cwinapp()有默认参数?见下:
(在cwinapp类定义中, cwinapp(lpctstr lpszappname = null); )
注意:cwinapp()函数中:
pthreadstate->m_pcurrentwinthread = this; 
pmodulestate->m_pcurrentwinapp = this
 //this 指向那里?是cwinapp对象还是ctestapp对象?
(this指向的是派生类cteapp对象,即theapp)
//???非常奇怪,我测试的this 指针指向基类呀!

调试:cwinapp::cwinapp();->cteapp theapp;(->cteapp ::cteapp())->cwinapp::cwinapp()->cteapp ::cteapp()->_twinmain(){}

4,_twinmain  函数中通过调用afxwinmain()函数来完成它要完成的功能。(afx*前缀代表这是应用程序框架函数,是一些全局函数,应用程序框架是一套辅助生成应用程序的框架模型,把一些类做一些有机的集成,我们可根据这些类函数来设计自己的应用程序,af是应用程序的框架的缩写)。
afxwinmain()函数路径:mfc / src / winmain.cpp:
而winmain()函数并不在winmain.cpp文件里。
在afxwinmain()函数中:
cwinapp* papp = afxgetapp();
说明:afxgetapp()获取一个指向cwinapp派生类对象(theapp)的指针。
papp调用三个函数,这三个函数完成设计窗口类、注册窗口类、创建窗口、显示窗口、更新窗口、消息循环、消息处理函数。pthread->initinstance()是三个函数当中的一个,pthread与papp等价的,它完成窗口初始化工作,完成窗口的注册,完成窗口的创建,显示和更新。
 首先调用 papp->initapplication(),用来做内部初始化管理用的。
//_afxwin_inline cwinapp* afxapi afxgetapp()
// { return afxcurrentwinapp; }

调用pthread->initinstance()
说明:pthread也指向theapp,由于基类中virtual bool initapplication()定义为虚函数,所以调用pthread->initinstance()时候,调用的是派生类ctestapp的initinstance()函数。

nreturncode = pthread->run();
说明:pthread->run()完成了消息循环。

5,注册窗口类:afxenddeferregisterclass(); //该函数会先判断要注册的窗口类是否已经注册过了
afxenddeferregisterclass()函数所在文件:mfc|src|appcore.cpp
bool afxapi afxenddeferregisterclass(long ftoregister){...}
说明:设计窗口类:在mfc中事先设计好了几种缺省的窗口类,根据不同的应用程序的选择,调用afxenddeferregisterclass()函数注册所选择的窗口类。
调试:cwinapp::cwinapp();->cteapp theapp;(->cteapp ::cteapp())->cwinapp::cwinapp()->cteapp ::cteapp()->_twinmain(){}//进入程序
->afxwinmain();->papp->initapplication();->pthread->initinstance()//父类initinstance虚函数;->cteapp::initinstance()//子类实现函数;->afxenddeferregisterclass(long ftoregister)//注册所选择的窗口类(出于文档管理,注册提前,正常的应在precreatewindow中进行注册)//之后进入创建窗口阶段(以下再不做调试)

6,precreatewindow()://这里面会调用afxenddeferregisterclass()注册窗口类
bool cmainframe::precreatewindow(createstruct& cs) //& cs 是一个引用,
 //对cs的修改,会在基类中体现,这样我们就有机会修改窗口的外观
{
 if( !cframewnd::precreatewindow(cs) )
  return false;
 return true;
}
说明:
cframewnd::precreatewindow()函数所在文件:mfc|src|winfrm.cpp
bool cframewnd::precreatewindow(createstruct& cs)
{
 if (cs.lpszclass == null)
 {
  verify(afxdeferregisterclass(afx_wndframeorview_reg));
   //判断afx_wndframeorview_reg型号窗口类是否注册,如果没有注册则注册
  cs.lpszclass = _afxwndframeorview;  // color_window background
   //把注册后的窗口类名赋给cs.lpszclass
 }

 if ((cs.style & fws_addtotitle) && afxdata.bwin4)
  cs.style |= fws_prefixtitle;

 if (afxdata.bwin4)
  cs.dwexstyle |= ws_ex_clientedge;

 return true;
}

其中:
virtual bool precreatewindow(createstruct& cs);//precreatewindow()是个虚函数,如果子类有则调用子类的。
#define verify(f)          assert(f)
#define afxdeferregisterclass(fclass) afxenddeferregisterclass(fclass)
define afx_wndframeorview_reg          0x00008
const tchar _afxwndframeorview[] = afx_wndframeorview;//wincore.cpp文件中,定义为全局数组。
//#define afx_wndframeorview  afx_wndclass("frameorview")

7,创建窗口:
创建窗口时的函数调用关系:
 create() ->  createex() -> precreatewindow() -> afxenddeferregisterclass()
 create()函数由谁调用?是由loadframe()调用。
create()函数路径:mfc|src|winfrm.cpp:
cframewnd::create(...){
 ...
 createex(...);//从父类继承来的,调用cwnd::createex().
  //后缀_ex表示是一个扩展函数
 ...
}

cwnd::createex()函数路径:mfc|src|wincore.cpp
bool cwnd::createex(...){
 ...
 if (!precreatewindow(cs))//虚函数,如果子类有调用子类的。
 {
  postncdestroy();
  return false;
 }
 ...
 hwnd hwnd = ::createwindowex(cs.dwexstyle, cs.lpszclass,
  cs.lpszname, cs.style, cs.x, cs.y, cs.cx, cs.cy,
  cs.hwndparent, cs.hmenu, cs.hinstance, cs.lpcreateparams);

 ...
}
说明:createwindowex()函数与createstruct结构体参数的对应关系,使我们在创建窗口之前通过可precreatewindow(cs)修改createstruct cs结构体成员来修改所要的窗口外观。precreatewindow(cs))//是虚函数,如果子类有调用子类的。
hwnd createwindowex(
  dword dwexstyle,     
  lpctstr lpclassname, 
  lpctstr lpwindowname,
  dword dwstyle,       
  int x,               
  int y,               
  int nwidth,          
  int nheight,         
  hwnd hwndparent,     
  hmenu hmenu,         
  hinstance hinstance, 
  lpvoid lpparam       
);
typedef struct tagcreatestruct { // cs
    lpvoid    lpcreateparams;
    hinstance hinstance;
    hmenu     hmenu;
    hwnd      hwndparent;
    int       cy;
    int       cx;
    int       y;
    int       x;
    long      style;
    lpctstr   lpszname;
    lpctstr   lpszclass;
    dword     dwexstyle;
} createstruct;

8,显示和更新窗口:
cteapp类,teapp.cpp中
m_pmainwnd->showwindow(sw_show);//显示窗口,m_pmainwnd指向框架窗口
m_pmainwnd->updatewindow();//更新窗口
说明:
class cteapp : public cwinapp{...}
class cwinapp : public cwinthread{...}
class cwinthread : public ccmdtarget
{
 ...
public:
 cwnd* m_pmainwnd;
 ...
...
}

9,消息循环:由pthread->run();完成。
int afxapi afxwinmain()
{ ...
 // perform specific initializations
 if (!pthread->initinstance()){...}
 //完成窗口初始化工作,完成窗口的注册,完成窗口的创建,显示和更新。
 nreturncode = pthread->run();
 //继承基类run()方法,调用cwinthread::run()来完成消息循环
 ...
}

cwinthread::run()方法路径:mfc|src|thrdcore.cpp
int cwinthread::run()
{ ...
  // phase2: pump messages while available
  do//消息循环
  {
   // pump message, but quit on wm_quit
   if (!pumpmessage())//取消息并处理
    return exitinstance();
   ...
  } while (::peekmessage(&m_msgcur, null, null, null, pm_noremove));
 ...
}
说明:
bool peekmessage(,,,,)函数说明
the peekmessage function checks a thread message queue for a message and places the message (if any) in the specified structure.
if a message is available, the return value is nonzero.
if no messages are available, the return value is zero.

/
bool cwinthread::pumpmessage()
{
 ...
 if (!::getmessage(&m_msgcur, null, null, null))//取消息
 {...}
 ...
 // process this message
 if (m_msgcur.message != wm_kickidle && !pretranslatemessage(&m_msgcur))
 {
  ::translatemessage(&m_msgcur);//进行消息(如键盘消息)转换
  ::dispatchmessage(&m_msgcur);//分派消息到窗口的回调函数处理(实际上分派的消息经过消息映射,交由消息响应函数进行处理。)
 }
 return true;
}

9,文档与视结构:
可以认为view类窗口是cmainfram类窗口的子窗口。
document类是文档类。
doc-view结构将数据本身与它的显示分离开。
文档类:数据的存储,加载
视类:数据的显示,修改

10,文档类,视类,框架类的有机结合:
在cteapp类cteapp::initinstance()函数中通过文档模板将文档类,视类,框架类的有机组织一起。
...
csingledoctemplate* pdoctemplate;
pdoctemplate = new csingledoctemplate(
 idr_mainframe,
 runtime_class(ctedoc),
 runtime_class(cmainframe),       // main sdi frame window
 runtime_class(cteview));
adddoctemplate(pdoctemplate);//增加到模板


下面给出cwnd 的仿真:
 
class  cwnd{
 public:
 bool createex(
  dword dwexstyle,
  lpctstr lpclassname,
  lpctstr lpwindowname,
  dword dwstyle,
  int x ,
  int y
  int nwidth,
  int nheight,
  hwnd hwndparent,
  hmwnu  hmenu,
  hinstance hinstance,
  lpvoid lpparam );
 bool showwindow(int ncmdshow);
 bool updatewindow();
 public:
  hwnd m_hwnd; //m_hwnd在构造函数中将其初始化为null
};


bool  cwnd::createex(
  dword dwexstyle,
  lpctstr lpclassname,
  lpctstr lpwindowname,
  dword dwstyle,
  int x ,
  int y
  int nwidth,
  int nheight,
  hwnd hwndparent,
  hmwnu  hmenu,
  hinstance hinstance,
  lpvoid lpparam );
{
 m_hwnd = ::createwindowex(dwexstyle, lpclassname, dwstyle,
  x, y, nwidth,nheight, hwndparent, hmenu, hinstance, lpparam);
 if(m_hwnd != null )
  return true;
 else
  return false;
}//end createex()

bool cwnd::showwindow (int ncmdshow)
{
 ::showwindow (m_hwnd,ncmdshow); //在函数前面加上的含义表示使用的是全局函数,
 //以前使用全局函数的时候可以直接写函数名就行了,现在加上“ :: ”是为了防止与 windows api 函数混淆
}

bool cwnd :: updatewindow()
{
 ::updatewindow ( m_hwnd);
}

int winapi winmain(
 hinstance hinstance,
 hinstance hprevinstance,
 lpstr  lpcmdline,
 int  ncmdshow)
{
 wndclass wndcls;
 wndcls.cbclsextra = 0;
 wndcls.cbwndextra = 0;
 .................
 registerclass (& wndcls);
 cwnd wnd; //wnd并不等价于窗口,当窗口销毁之后,c 对象还可以存在
 wnd.createex(dwexstyle, lpclassname, dwstyle,
  x, y, nwidth,nheight, hwndparent, hmenu, hinstance, lpparam);
 wnd.showwindow(sw_shownuormal); //注意这里不再需要传递hwnd句柄,因为wnd里面已经定义了句柄 m_hwnd
 wnd.updatewindow();
 
 
}//endof winmain() 


http://www.ngui.cc/el/5126849.html

相关文章

孙鑫vc学习笔记:第六讲

六、菜单 2006年8月3日 第六讲三个多小时,花了我两天时间才看完,然后用onenote花花绿绿地做了好多笔记,可以说是图文并茂,但是这里显示不出来,所以做了一张抓图,图片地址:http://img565.photo.1…

孙鑫vc学习笔记:第九讲外观

在网上搜索了很久都没有找到孙鑫vc视频教学第九讲的笔记,只好自己写了 九、外观1 http://img584.photo.163.com/goodmoood/61588745/1785749078.jpg 九、外观2 修改窗口的图标、光标和背景.jpg http://img584.photo.163.com/goodmoood/61588745/1785749281.jpg 九…

孙鑫vc学习笔记:第十一讲 坐标空间与各种转换的概念

孙鑫vc学习笔记:第十一讲 坐标空间与各种转换的概念 介绍一下坐标空间、逻辑空间、映射方式等概念microsoft windows 下的程序运用坐标空间和转换来对图形输出进行缩放,平移,旋转,斜切和反射。一个坐标空间是一个二维空间&#x…

孙鑫vc学习笔记:第十一讲 图形的保存与重绘方法一

图形的保存和重绘编写画图代码,设定一个标识,在onlbuttondown中保存鼠标按下去的点,在onlbuttonup中捕获鼠标弹起的点,利用switch语句分别画图。这是上节课的内容,上节课还讲了窗口重绘的原理,实际上分为两…

孙鑫vc学习笔记:第十一讲 如何把元文件保存到文件当中

如何把元文件保存到文件当中1.为“打开”,“保存”添加命令相应函数。2.用 copymetafile 拷贝元文件到指定文件中copymetafile 将windows格式的元文件拷贝到指定的文件当中。首先我们在“保存”命令响应函数onfilesave()中完成保存元文件到文件的功能, …

孙鑫vc学习笔记:第十一讲 图形重绘方法三 利用兼容dc

介绍利用兼容dc保存图形与重绘图形的方式1.构造兼容dc对象:cdc m_dccompatible2.在cgraphicview::onlbuttonup写下面代码3.在cgraphicview::ondraw中写入下面代码:cbitmap::createcompatiblebitmap 通过指定的宽高创建一个兼容位图。初始化一个与指定设…

孙鑫vc学习笔记:第十一讲 如何使窗口具有滚动条

如何使窗口具有滚动条?本程序的cgraphicview 类是从view类继承的 class cgraphicview : public cview首先将基类改成cscrollview class cgraphicview : public cscrollview然后将源文件cpp文件中的cview全部替换成cscrollview在文件中替换字或词的步骤, …

孙鑫vc学习笔记:第十一讲 图形重绘方法二 利用元文件

介绍两种保存图形与重绘图形的方式第一种,要利用要一个类 cmetafiledc第一步创建一个cmetafiledc 对象。接着调用cmetafiledc 构造器,然后再调用create 函数 创建一个设备上下文与cmetafiledc 对象关联起来。 下一步给cmetafiledc 对象发送一系列的cdc命…

选美,为我妹妹投一票,5号选手

2006年33届环球国际小姐中国福建区总决赛,我妹妹是5号选手陈小燕,短信投票占40%啊!感谢您编写短信v5发送到发送至880866(移动:全国有效)、960666(联通:全国有效)、936899…

孙鑫vc学习笔记:第十二讲 介绍常量指针、指针常量,文本、二进制文件

◆指向常量的指针 它指向的内容是常量,不能修改;但是指针本身存放的是指针值,可以修改。 char ch[5]"list" 这种赋值形式只能在数组定义的同时进行。 常量字符串会自动加上/0,所以字符串长度为五 通常,…
网站地图