软件工具与环境重难点分析_第1页
软件工具与环境重难点分析_第2页
软件工具与环境重难点分析_第3页
软件工具与环境重难点分析_第4页
软件工具与环境重难点分析_第5页
已阅读5页,还剩43页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

软件工具与环境重难点分析

第一部份Windows程序设计的原理

一、Win32基本概念

1、Win32程序开发流程

Windows程序分为"程序代码"和"UI(UserInterface用户接口)资源”两大部分,最

后以RC编译器整合为一个完整的EXE文档(见图1)。

2、需要什么函数库(.LIB)

Windows支持动态链接。即应用程序所调用的WindowsAPI函数是在“执行时期”才链接

的(并不是扩展名为.dll的文件才是动态链接库,其实.exe、.dll、.fon、.mod、.drv、.ocx都

是所谓的动态链接库)。Windows程序调用的函数分为CRuntimes以及WindowsAPI两大部

分。

(1)CRuntimes

L1BC.LIB——这是CRuntime函数库的静态链接版本。

MSVCRT.LIB——这是CRuntime函数库的静态链接版本(MSVCRT.LIB)的import函

数库。

(2)WindowsAPI

由操作系统本身(主要是Windows三大模块GDI32.DLL、USER32.DLL和

KERNEL32.DLL)提供。

32位Windows的三大模块所对应的import函数库分别为GDI32.LIB,USER32.LIB和

KERNEL32.LIB。

(3)新增的WindowsAPI

Windows发展到今,逐渐新增的一些API函数并未放在GDI32.DLL、USER32.DLL和

KERNEL32.DLL三大模块中,而是放在诸如COMMDLG.DLL、TOOLHELP.DLL中。如果

要使用这些APIs函数,链接时还需加上这些DLLs所对应的import函数库(如

COMDLG32.LIB、TH32.LIB)。

3、需要什么头文件(.H)

(1)所有Windows程序都必须包含WINDOWS.Ho因为WINDOWS.H有三大模块所

提供的API函数说明。

(2)如果要使用其它systemDLLs(如COMMDLGDLL、MAP1.DLL或TAPI.DLL等),

就需包含对应的头文件(如COMMDLG.H、MAPI.H或TAPLH等)

4、以消息为基础,以事件驱动之(见图2)——(重点、难点)

图2Windows程序与操作系统之间的关系图

Windows程序的运行是靠外部发生的事件来驱动。即程序(利用一个while循环)不断

等待任何可能的输入,然后作出判断,再作适当的处理。而“输入”是由操作系统的USER模

块捕捉到之后,以消息的形式(一种数据结构)进入程序中。

如果对应用程序获得的各种“输入”进行分类,可以分为由硬件所产生的消息(如鼠标

移动或键盘被按下),放在系统队列(systemqueue)中;以及由Windows系统或其它Windows

程序传送来的消息,放在程序队列中。应用程序调用GetMessageAPI获取一个消息,程序

的生命靠它来推动。

每一个Windows程序都有如下循环:

MSGmsg;

while(GelMessage(&msg,NULL,NULL,NULL)){

TranslateMessage(&msg);

DispatchMessage(&msg);

)

每一个窗口获得一个消息后,都有一个“窗口函数”负责处理消息。程序员必须负责设计

这个所谓的“窗口函数”。如果窗口获得一个消息,则这个窗口函数必须判断消息类别,决

定处理方式。

以上就是Windows程序设计最重要的概念。至于窗口的产生与显示,十分简单,有专

门的API函数负责完成。

二、C++的重要性质——(重点)

1、类及其成员——封装

例1:

#include<iostream.h>

#include<string.h>

classCSquare

(

private:

char*m_color;

intm_length;

public:

voidsetcolor(char*color)

(

m_length=strlen(color);

m_color=newchar[m_length+l];

strcpy(m_color,color);

)

voiddisplayO

(

cout«m_color«endl;

)

);

voidmain()

(

CSquaresquare;

square.setcolor(nRED");

square.displayO;

把数据成员声明为private,不允许外界随意存取,只能通过特定的接口(成员函数)来

操作,这就是面向对象的封装特性。

2、基类与派生类——继承

(1)派生类与基类的关系是“IsKindOE的关系。

图3派生类与基类关系图

例2(见图3):

#include<iostream.h>

classCShape

(

private:

intm_color;

public:

voidsetcolor(intcolor)

(

m_color=color;

)

);

classCRect:publicCShape

(

public:

voiddisplay()

(

cout«nRectangle"«endl;

)

);

classCEllipse:publicCShape

(

public:

voiddisplayO

cout«,,Ellipse,,«endl;

);

classCTriangle:publicCShape

(

public:

voiddisplayO

(

cout«nTrianglen«endl;

}

);

classCSquare:publicCRect

(

public:

voiddisplayO

(

cout«"Square"«endl;

)

);

classCCircle:publicCEllipse

(

public:

voiddisplayO

(

cout«"Circlen«endl;

)

);

voidmain()

(

CSquaresquare;

CRectrecti,rect2;

CCirclecircle;

square.setcolor(l);

square.displayO;

rectl.setcolor(2);

recti.displayO;

rect2.setcolor(3);

rect2.display();

circle.setcolor(4);

circle.displayO;

(2)三个重要结论——(重点、难点)

1)如果用一个“基类的指针”指向“派生类的对象”,那么由该指针只能够调用基类所定

义的函数(见图4)。

classCBase__________7CBase*pBase;

BaseFunc()/CDerivedDeri;

/pBase=&Deri;

/pBase只能调用BaseFunc()

________________/

classCDerived夕

DeriFuncO

图4

2)如果用•个“派生类的指针”指向•个“基类的对象”,必须先做明显的类型转换。这

种作法很危险,不符合真实生活经验,在程序设计上也会给程序员带来困惑(见图5)。

CDerived*pDeri;

CBaseBase;

pDeri=&Base;

这种作法很危险。

3)如果基类和派生类都定义了“相同名称的成员函数“,那么通过对象指针调用成员函

数时,必须根据该指针的原始类型而定,而不是根据指针实际所指的对象类型而定(图6)。

CBase*pBase;

CDerived*pDeri;

pBase->CommFunc()是指CBase::CommFunc()

pDeri->CommFunc()是指CDerived::CommFunc()

图6

3、虚函数与多态——(重点)

(1)虚函数是对“如果用一个基类的指针指向一个派生类的对象,那么通过该指针只

能够调用基类所定义的成员函数''这条规则反其道而行之的设计。

例3(见图3):

#include<iostream.h>

classCShape

private:

intm_color;

public:

voidsetcolor(intcolor)

{

m_color=color;

}

virtualvoiddisplayO

(

cout«"Shapeu«endl;

)

);

classCRect:publicCSh叩e

(

public:

virtualvoiddisplayO

(

cout«nRectanglen«endl;

)

);

classCEllipse:publicCShape

|

public:

virtualvoiddisplayO

(

cout«nEllipsen«endl;

)

);

classCTriangleipublicCShape

(

public:

virtualvoiddisplayO

(

cout«nTriangle"«endl;

)

);

classCSquare:publicCRect

(

public:

virtualvoiddisplayO

cout«"Squaren«endl;

)

);

classCCircle:publicCEllipse

public:

virtualvoiddisplayO

cout«"Circle"«endl;

);

voidmain()

CShapeaShape;

CEllipseaEllipse;

CCircleaCircle;

CTriangleaTriangle;

CRectaRect;

CSquareaSquare;

CShape*pShape[6]={&aShape,&aEllipse,&aCircle,&aTriangle,&aRect,&aSquare};

for(inti=0;i<6;i++)

pShape[il->display();

(2)用相同的指令调用不同的函数,这种性质就称为多态。

(3)重要结论——(重点、难点)

1)如果要在派生类中重定义一个成员函数,那么应该在基类中把该成员函数设置为

virtualo

2)如果基类中的虚函数不允许被调用,就应该将其设置为纯虚函数(在函数声明之后

加上“=0”即可)。

3)拥有纯虚函数的类称为抽象类。抽象类虽然不能产生对象实例,但是可以拥有指向

抽象类的指针,以便于操作抽象类的各个派生类。

4)虚函数被派生类继承后仍然是虚函数,在派生类中可以省略关键字virtual。

5)如果是指向对象的指针或对象引用,或者是由成员函数调用虚函数;则将采用动态

联编方式调用虚函数。

6)如果用一般类型的标识对象来调用虚函数操作,则将采用静态联编方式调用虚函数。

(4)动态联编的实现机制——(参考资料)

1)对每一个“内含虚函数的类”的对象,C++编译器都会为它生成一个虚拟函数表(常

称为vtable),表中的每个元素都指向一个虚函数的入口地址。止匕外,编译器也为该类对象

增加•个数据成员,是一个指向该虚函数表的指针(常称为vpir)。

2)当通过对象调用虚函数时,事实上是通过vptr找到虚拟函数表,再找出虚函数的真

正入口地址。

3)虚拟函数表的内容是根据类中虚函数声明的次序,一一填入函数指针。

4)派生类会继承基类的虚拟函数表(以及所有其它可以继承的成员),当在派生类中改

写虚函数时,虚函数表就受到了影响:表中元素所指的函数地址将不再是基类的函数地址,

而是派生类的函数地址。

ClassA

的对象vtable

ClassB的对象

图7虚函数表

例4(见图7):

#include<iostream.h>

classClassA

(

public:

intm_datal;

intm_data2;

voidfuncl(){}

voidfunc2(){}

virtualvoidvfuncl(){}

virtualvoidvfunc2(){}

);

classClassB:publicClassA

public:

intm_data3;

voidfunc2(){}

virtualvoidvfuncl(){}

);

classClassC:publicClassB

(

public:

intm_datal;

intm_data4;

voidfunc2(){}

virtualvoidvfuncl(){}

);

voidmain()

(

cout«sizeof(ClassA)«endl;

cout«sizeof(ClassB)«endl;

cout«sizeof(ClassC)«endl;

ClassAa;

ClassBb;

ClassCc;

b.m_datal=l;

b.m_data2=2;

b.m_data3=3;

c.m_datal=l1;

c.m_data2=22;

c.m_data3=33;

c.m_data4=44;

c.ClassA::m_datal=l11;

cout«b.m_data1«endl;

cout«b.m_data2«endl;

cout«b.m_data3«endl«endl;

cout«c.m_data1«endl;

cout«c.m_data2«endl;

cout«c.m_data3«endl;

cout«c.m_data4«endl;

cout«c.ClassA::m_datal«endl«endl;

cout«&b«endl;

cout«&(b.m_datal)«endl;

cout«&(b.m_data2)«endl;

cout«&(b.m_data3)«endl«endl;

cout«&c«end1;

cout«&(c.m_datal)«endl;

cout«&(c.m_data2)«endl;

cout«&(c.m_data3)«endl;

cout«&(c.m_data4)«endl;

cout«&(c.ClassA::m_datal)«endl;

)

例5:------(难点、重点)

#include<iostream.h>

classCObject

(

public:

virtualvoidSerialize()

(

cout«nCObject::Serialize()\n\nn;

)

);

classCDocumentipublicCObject

(

public:

intm_datal;

voidfunc()

(

cout«,'CDocument::func(),'«endl;

Serialize();

)

virtualvoidSerialize()

(

cout«HCDocument::Serialize()\n\n";

)

);

classCMyDoc:publicCDocument

(

public:

intm_data2;

virtualvoidSerialize()

(

cout«nCMyDoc::Serialize()\n\nM;

)

);

voidmain()

CMyDocmydoc;

CMyDoc*pmydoc=newCMyDoc;

cout«M#ltesting"«endl;

mydoc.func();

cout«M#2testing"«endl;

((CDocument*)(&mydoc))->func();

cout«M#3testing"«endl;

pmydoc->func();

cout«M#4testing"«endl;

((CDocument)mydoc).func();

)

三、MFC类层次结构(图8)——(重点)

图8MFC几个最重要的类的层次关系图

例6:

//MFC.H

#include<iostream.h>

classCObject

(

public:

CObjectO

(

cout«"CObjectConstructor\nu;

)

-CObjectO

(

cout«"CObjectDestructor\nH;

)

};

classCCmdTarget:publicCObject

(

public:

CCmdTarget::CCmdTarget()

(

cout«"CCmdTargetConstructorXn";

)

CCmdTarget:>CCmdTarget()

(

cout«"CCmdTargetDestructor\n";

)

classCWinThread:publicCCmdTarget

(

public:

CWinThread::CWinThread()

cout«"CWinThreadConstructor\nM;

);

classCWinApp:publicCWinThread

public:

CWinApp*m_pCurrentWinApp;

public:

CWinAppO

(

cout«"CWinAppConstructor\nH;

m_pCurrentWinApp=this;

)

〜CWinAppO

{

cout«nCWinAppDestructor\nu;

)

);

classCDocument:publicCCmdTarget

(

public:

CDocument()

(

cout«nCDocumentConstructor";

}

-CDocument()

(

cout«HCDocumentDestructor\nM;

}

);

classCWnd:publicCCmdTarget

(

public:

CWnd()

(

cout«"CWndConstructor\n";

)

〜CWnd()

(

cout«nCWndDestructor\nH;

)

);

classCFrameWnd:publicCWnd

public:

CFrameWnd()

{

cout«MCFrameWndConstructor3”;

)

-CFrameWnd()

(

cout«,,CFrameWndDestructor\nM;

)

);

classCView:publicCWnd

(

public:

CView()

(

cout«"CViewConstructor^”;

)

~CView()

(

cout«"CViewDestructor\n";

)

);

CWinApp*AfxGetAppO;

//MFC.CPP

#include"my.h”

externCMyWinApptheApp;

CWinApp*AfxGetAppO

(

returntheApp.m_pCurrentWinApp;

}

//My.H

#include<iostream.h>

#include"mfc.h"

classCMyWinApp:publicCWinApp

(

public:

CMyWinAppO

(

cout«HCMyWinAppConstructor\n";

)

〜CMyWinApp。

cout«HCMyWinAppDestructor\nH;

)

);

classCMyFrameWnd:publicCFrameWnd

(

public:

CMyFrameWnd()

(

cout«"CMyFrameWndConstructor\n";

)

~CMyFrameWnd()

(

cout«"CMyFrameWndDestructor\n";

)

);

//My.CPP

#include"my.h"

CMyWinApptheApp;

voidmain()

(

CWinApp*pApp=AfxGetApp();

)

由上例可知:——(重点)

1、全局对象的建立(构造函数的调用)比程序进入点(在DOS环境为main(),在Windows

环境为WinMain())更早。

2、main。函数通过调用全局函数AfxGetApp()以取得全局对象theApp的指针。这完全

是MFC程序设计的方法。

四、MFC程序的初始化过程——(重点、难点)

1、MFC程序也是一个Windows程序,它的内部一定也有窗口注册操作,有窗口产生

操作,有消息循环操作,也有窗口函数。这些操作流程正是任何MFC程序的初始化过程的

简化。

2、现在初始化应用InitApplication()和初始化实例Initlnstance()在MFC中是CWinApp

类的两个虚函数。

3、InitApplication()负责“每—■个程序只做一次”的操作;而Initlnstance()负责“每—■个实

例都有要做一次”的操作。

4、通常MFC会(并有能力)帮我们注册一些标准的窗口类(当然也就准备好了一些

标准的窗口函数),而我们(应用程序设计者)应该在自己的CMyWinApp中改写Initlnstance

函数,并在其中将窗口产生出来,这样才能在标准的窗U类中指定标题和菜单。

例7:

//MFC.H

#defineBOOLint

#defineTRUE1

#defineFALSE0

#include<iostream.h>

classCObject

(

public:

CObject()

(

)

-CObject()

(

)

);

classCCmdTargetrpublicCObject

(

public:

CCmdTarget()

(

)

~CCmdTarget()

(

)

);

classCWinThread:publicCCmdTarget

(

public:

CWinThreadO

|

)

-CWinThreadO

(

}

virtualBOOLInitlnstance()

(

cout«"CWinThread::InitInstance\n";

returnTRUE;

)

virtualintRun()

{

cout«"CWinThread::Run\n";

return1;

);

classCWnd;

classCWinApp:publicCWinThread

(

public:

CWinApp*m_pCurrentWinApp;

CWnd*m_pMainWnd;

public:

CWinAppO

(

m_pCurrentWinApp=this;

}

〜CWinAppO

virtualBOOLInitApplication()

(

cout«,'CWinApp::InitApplication\n,';

returnTRUE;

)

virtualBOOLInitlnstance()

(

cout«"CWinApp::InitInstance\n";

returnTRUE;

)

virtualintRun()

(

cout«"CWinApp::Run\n";

returnCWinThread::Run();

)

);

classCDocument:publicCCmdTarget

(

public:

CDocument()

{

)

-CDocument()

);

classCWnd:publicCCmdTarget

(

public:

CWnd()

(

)

~CWnd()

{

)

virtualBOOLCreate();

BOOLCreateEx();

virtualBOOLPreCreateWindow();

);

classCFrameWnd:publicCWnd

(

public:

CFrameWnd()

(

)

-CFrameWnd()

(

)

BOOLCreate();

virtualBOOLPreCreateWindow();

);

classCView:publicCWnd

(

public:

CView()

{

)

~CView()

CWinApp*AfxGetAppO;

//MFC.CPP

#include"my.h"

externCMyWinApptheApp;

BOOLCWnd::Create()

cout«nCWnd::Create\n";

returnTRUE;

BOOLCWnd::CreateEx()

{

cout«"CWnd::CreateEx\nn;

PreCreateWindow();//5.调用CFrameWnd::PreCreateWindow()

returnTRUE;

)

BOOLCWnd::PreCreateWindow()

(

cout«"CWnd::PreCreateWindow\n";

returnTRUE;

BOOLCFrameWnd::Create()

(

cout«nCFrameWnd::Create\n";

CreateEx();〃4.调用CWnd::CreateEx()

returnTRUE;

BOOLCFrameWnd::PreCreateWindow()

(

cout«nCFrameWnd::PreCreateWindow\n";

returnTRUE;

CWinApp*AfxGetAppO

(

returntheApp.m_pCurrentWinApp;

}

//My.H

#include<iostream.h>

#include"mfc.h"

classCMyWinApprpublicCWinApp

(

public:

CMyWinAppO

〜CMyWinApp。

(

)

virtualBOOLInitlnstance();

}:

classCMyFrameWnd:publicCFrameWnd

(

public:

CMyFrameWnd();

〜CMyFrameWnd()

//My.CPP

#include"my.h"

CMyWinApptheApp;

BOOLCMyWinApp::lnitlnstance()

(

cout«',CMyWinApp::InitInstance\n,';

m_pMainWnd=newCMyFrameWnd;〃2.调用CMyWinApp::CMyFrameWnd()

returnTRUE;

)

CMyFrameWnd::CMyFrameWnd()

(

cout«"CMyFrameWnd::CMyFrameWnd\nn;

Create();//3.调用CFrameWnd::Create()

)

voidmain()

(

CWinApp*pApp=AfxGetAppO;

pApp->InitApplication();

pApp->InitInstance();〃1.调用CMyWinApp::InitInstance()

pApp->Run();

)

五、MFC建立窗口程序的概念——(重点、难点)

1、需包含的头文件----afxwin.h

用MFC编写窗口程序时,必须包含afxwin.h头文件。在该头文件中定义了所有的MFC

类。

2、应用程序对象与窗口框架对象

它们是在应用程序中必须建立的两个最基本的对象。

(1)应用程序对象代表整个应用程序。因此每个应用程序里,都会建立一个应用程序

类(继承CWinApp类),这个应用程序类将用于产生应用程序对象。

(2)窗口框架对象代表应用程序界面。

(3)在建立应用程序对象过程中,该对象将会负责建立窗口框架对象,并将继承的

m_pMainWnd属性指向所使用的窗口框架对象,最后显示窗口。

例8:

#include<afxwin.h>

#includeuMyApp.hn

classCMyFrameWnd:publicCFrameWnd

(

public:

CMenu*pMenu;

CMyFrameWnd()

(

Create(NULL,"Hello");

pMenu=newCMenu;

pMenu->LoadMenu(IDR_MENU1);

SetMenu(pMenu);

classCMyWinApprpublicCWinApp

(

public:

BOOLInitlnstance()

(

CFrameWnd*Frame=newCMyFrameWnd;

m_pMainWnd=Frame;

Frame->ShowWindow(SW_SHOW);

returntrue;

)

);

CMyWinApptheApp;

3、CWinApp类与程序进入点

(1)自定义应用程序类

自定义应用程序类,需要完成下列工作:

1)继承CWinApp类

classCMyWinApp:publicCWinApp

);

2)重定义CWinApp:Unitinstance函数,该函数是窗口程序的进入点,返回值为BOOL。

classCMyWinApp:publicCWinApp

(

public:

BOOLInitlnstance()

);

(2)程序进入点

当建立继承于CWinApp类的应用程序类时,必须重新定义程序进入点函数

CWinApp:Jnitlnstance,通常在该函数中将完成下列工作:

1)产生窗口框架对象

CFrameWnd*Frame=newCMyFrameWnd;

2)将CWinApp::m_pMainWnd属性设置为窗口框架对象的指针

m_pMainWnd=Frame;

m_pMainWnd=newCMyFrameWnd;

3)建立窗口框架(也可以自定义)

m_pMainWnd->Create(NULL,"Hello");

4)在屏幕上显示窗口框架对象

Frame->ShowWindow(SW_SHOW);

(3)建立应用程序对象

完成自定义应用程序类后,必须利用该类建立一个应用程序对象。

CMyWinApptheApp;

当应用程序对象建立时,将会调用Initlnstance函数开始程序的执行。

5、自定义窗口框架

(1)必须继承CFrameWnd类,建立自定义的窗口框架类。并在资源文件中定义该窗

口框架所需用的元件再由窗口框架对象载入这些资源。

classCMyFrameWnd:publicCFrameWnd

(

);

(2)资源文件的建立

由于窗口框架类是负责建立应用程序对象所使用的窗口框架对象,即应用程序的窗口界

面。而窗口界面对象中所使用的元件(如菜单等),将定义在资源文件中。因此可以利用资

源编辑器来完成资源文件的建立,并自动产生定义识别字的头文件。

(3)在程序中操作资源对象

在程序中欲操作资源文件中的资源(如菜单等)对象时,首先要在程序中建立••个对应

的对象,以该对象代表资源文件中的相应资源;然后在程序中便可以运用该对象操作资源文

件中的资源。

(4)在窗口框架中建立菜单

必须先在程序中建立一个对应于菜单资源的对象。可以在自定义的窗口框架类的构造函

数中建立一个CMenu菜单对象,并以CMenu::LoadMenu为该对象载入菜单资源,再利用

CWnd::SetMenu函数将菜单对象设定给窗口框架对象。

classCMyFrameWnd:publicCFrameWnd

public:

CMenu*pMenu;

CMyFrameWnd()

pMenu=newCMenu;

pMenu->LoadMenu(IDR_MENU1);

SetMenu(pMenu);

);

6、有关函数说明——(参考资料)

(1)、BOOLvirtualCFrameWnd::Create(LPCTSTRlpszClassName,

LPCTSTRIpszWindowName,DWORDdwStyle=WS_OVERLAPPEDWINDOW,

constRECT&rectDefault,CWnd*pParentWnd=NULL,

LPCTSTRlpszMenuName=NULL,DWORDdwExStyle=O,

CCreateContext*pContext=NULL)

1)函数功能:建立窗口框架对象。

2)参数说明

LPCTSTRIpszClassName指向•个用于存储窗口类名的数据结构。该参数设为NULL

时,表示使用MFC预设的窗口框架产生一个标准的窗口。

LPCTSTRIpszWindowName窗口标题栏内的文字。

DWORDdwStyle指定窗口形式的特性参数,预设为WS_OVERLAPPEDWINDOW。

constRECT&rectDefault设定窗口的大小和位置,其中位置坐标以左上角为窗口原点。

CWnd*pParentWnd=NULL指向父窗口的指针。若窗口为最上层的窗口则设定为

NULLo

LPCTSTRlpszMenuName=NULL指向一个定义在资源文件(RC文件)的菜单名称。

如果用识别字代表菜单时,必须用MAKEINTRESOURCE(识别字)函数传入参数。

DWORDdwExStyle=O指定延伸窗口形式。

CCreateContext*pContext=NULL若窗口具备Document/View结构时,需指定此参数,

否则采用预设值。

(2)BOOLCWnd::ShowWindow(intnCmdShow)

1)函数功能:显示窗口框架对象。

2)参数说明

intnCmdShow控制窗口显示方式的参数。如SW_HIDE、SW_MINIMIZE、

SW_RESTORE、SW_SHOW、SW_SHOWMAXIMIZED、SW_SHOWMINIMIZED、

SW_SHOWNORMAL、SW_SHOWMINNOACTIVE、SW_SHOWNA、

SW_SHOWNOACTIVATEo

(3)、BOOLCMenu::LoadMenu(UINTnIDResource)

1)函数功能:如果装载菜单资源成功,返回非零值,失败则返回零值。

2)参数说明

UINTnIDResource菜单识别字。

LPCTSTRIpszResourceName菜单名。

(4)BOOLCWnd::SetMenu(Cmenu*pMenu)

1)函数功能:设定当前窗口框架使用的菜单。

2)参数说明

Cmenu*pMenu菜单对象指针。指向窗口框架所要使用的菜单对象。

六、窗口消息的传递与处理——(难点)

在Windows操作系统下,操作系统不断由外围设备获得消息,并传递给应用程序,而

应用程序对消息的响应是通过消息映射表来完成的。

1、消息映射表的声明

(1)首先必须在负责响应消息的类体中声明消息映射表:

DECLARE_MESSAGE_MAP()

(2)然后在类体外建立消息映射表,声明消息响应项:

BEGIN_MESSAGE_MAP(类名,基类名)

消息响应项

END_MESSAGE_MAP()

2、消息种类与响应项的定义

信息响应项的定义按消息种类的不同可分为二种:

(1)标准系统消息

1)标准系统消息是由操作系统产生的,例如鼠标左键被按下或移动鼠标等。而接收并

处理这类消息的类必须派生于CWnd类。

2)响应这类消息的消息响应项的命名规则为ON_WM_XXX,如鼠标移动的消息响应

项为:

ON_WM_MOUSEMOVE()

3)对应于标准系统消息的响应函数名,MFC均已定义。如鼠标移动的消息响应函数为:

afx_msgvoid类名::OnMouseMove(UNITnFlags,CPointpoint)

(

}

其中:point传入参数,表示的光标坐标;

nFlags传入参数,表示几个特殊按键的状态:

nFlags说明

MK_CONTROL键盘上CTRL键被按下

MK.LBUTTON鼠标左键被按下

MK_MBUTTON鼠标中键被按下

MK_RBUTTON鼠标右键被按下

MK_SHIFT键盘上SHIFT键被按下

(2)命令消息

1)命令消息是山用户建立的菜单、工具栏、控制选项等窗口元件被选取时所产生的消

息。响应这类消息的类必须派生于CCmdTargel类。

2)这类消息响应项的定义为:

ON_COMMAND(消息代号,响应函数名)

其中:消息代号是建立资源对象时所设置的识别字。

例如:声明OnExit函数处理IDM_EXIT消息的消息响应项为

ON_COMMAND(IDM_EXIT,OnExit)

3)对应于命令消息的响应函数为:

afx_msgvoid类名::响应函数名()

例如:处理IDM_EXIT消息的响应函数OnExit为:

afx_msgvoid类名::OnExit()

3、有关函数说明——(参考资料)

(1)CWnd*CWnd::SetCapture()

函数功能:设置当前执行的窗口程序取得鼠标消息接收权。若成功,则返回前一个取得

鼠标消息接收权的窗口对象指针。若在此次设置鼠标消息接收权前,未设置取得鼠标消息接

收权的窗口对象,则返回NULL值。

(2)CWnd*CWnd::GetCapture()

函数功能:返回当前取得鼠标消息接收权的窗口指针。若当前执行中的窗口未取得鼠标

消息接收权,则返回NULL值。

(3)CWnd*CWnd::ReleaseCapture()

函数功能:释放当前的窗口所取得的鼠标消息接收权。若成功,则返回非零值。

(4)virtualBOOLCWnd::DestoryWindow()

函数功能:清除窗口对象。若成功,则返回非零值;否则返回0。

(5)intCWnd::MessageBox(LPCTSTRIpszText,LPCTSTRlpszCaption=NULL,

UNITnType=MB_OK)

1)函数功能建立消息框。若成功建立,则返回用户在该消息框中按下按钮所传出的

消息。

2)参数说明

LPCTSTRIpszText在消息框中的显示文本。

LPCTSTRlpszCaption=NULL在消息框标题栏中的文本。

UNITnType=MB_OK设置消息框的式样。

(6)COLORREFCDC::SetPixel(POINTpoint,COLORREFcrColor)

COLORREFCDC::SetPixel(intx,inty,COLORREFcrColor)

1)函数功能在画布的x,y坐标或point位置上画出一个颜色为crColor的点。若绘

制成功则返回绘于画布上的颜色值。若不成功,则返回-1。

2)参数说明

POINTpoint或intx,inty代表欲绘制点的位置坐标。

COLORREFcrColor代表欲绘制点的颜色。

第二部份多任务与多线程编程

一、Windows程序的生与死

在了解Windows程序的架构以及它与Windows系统之间的关系后,对Windows消息种

类以及产生时机的透彻了解,正是程序设计的关键。下面以窗口的产生与死亡,说明消息的

产生与传递,以及应用程序的生与死。

1、程序初始化过程中调用CreateWindow,为程序建立了•个窗口,作为程序的屏幕舞

台。CreateWindow产生窗口之后会送出WM_CREATE直接给窗口函数,后者于是可以在此

时做些初始化操作(例如配置内存、打开文件、读初始数据等。

2、在程序活着的过程中,不断以GetMessage从消息队列中获取消息。如果这个消息是

WM_QUIT,GetMessage会返回0而结束while循环,进而结束整个程序。

3、DispatchMessage通过WindowsUSER模块的协助和监督,把消息分发给窗口函数。

消息将在该处被判别并处理。

4、程序不断进行上述2和3的操作。

5、当操作者按下系统菜单中的Close命令项时,系统送出WM_CLOSE。通常程序的窗

口函数不拦截此消息,于是DefWindowProc处理它。

6、DefWindowProc收到WM_CLOSE后调用DestroyWindow把窗口清除。

DefWindowProc本身又会送出WM_DESTROY»

7、程序对MW_DESTROY的标准反应是调用PostQuitMessage。

8、PostQuitMessage没有什么操作,只送出WM_QUIT消息,准备让消息循环中的

GetMessage获取此消息,结束消息循环。

二、空闲时间的处理

1、空闲时间的概念

所谓空闲时间(idletime)是指“系统中没有任何消息等待处理”的时间。例如没有任何

程序使用定时器(timer,它会定时送来WM_TIMER),使用者也没有按键盘和鼠标或操作

任何外设,那么系统就处于所谓的空闲时间。

2、空闲时间的处理

空闲时间经常发生。后台工作最适合在空闲时间完成。传统的SDK程序如果要处理空

闲时间,可以用下列循环取代WinMain中的传统消息循环:

while(TRUE){

if(PeekMessage(&msg,NULL,0,0,PM_REMOVE){

if(msg.message==WM_QUIT)

break;

TranslateMessage(&msg);

DispatchMessage(&msg);

)

else

Onldle();

)

原因是PeekMessage和GetMessage的性质不同:它们都是从消息队列中获取消息,如

果没有消息,程序的主执行线程(primary由read,是一个UI执行线程)会被操作系统挂起。

当操作系统再次回来照顾这一执行线程时,发现消息队列中仍然是空的,这时两个函数的行

为就不同了:

(1)GetMessage会过门不入,于是操作系统再去照顾其它程序。

(2)PeekMessage会取回控制权,使程序得以执行一段时间。于是上述消息循环进入

Onldle函数中。

三、Windows的多任务

1、Windows3.X的协同式多任务

Windows3.X都允许同时执行多个程序。但分享CPU是程序的责任(即应用程序具有

对CPU的控制权)。如果有一个程序不放弃CPU(许多程序采用传统的消息循环,而拒绝

与其它程序共享资源),其它程序只有挂起而无法响应操作。

2、Windows9X的抢先式多任务

操作系统能够强迫应用程序把CPU分享给其它程序。即程序对CPU的占用时间由系统

控制,系统为每个程序分配一定的CPU时间,当程序的运行超过规定时间后,系统就会中

断该程序并把CPU控制权让给其它程序。

3、多线程多任务

在Win32系统中,执行一个程序,必然会产生一个进程;当一个进程建立后,主线程

也产生了。多任务是指系统可以同时运行多个进程,而每个进程也可同时执行多个线程。-

个程序可以运行多个线程,每个线程独立地执行程序代码中的一组语句。

四、进程与线程

通常用进程(process)表示一个执行中的程序,并认为它是CPU调度单位。事实上线

程(thread)才是调度单位。

进程是应用程序的运行实例。每个进程都有自己私有的虚拟地址空间。每个进程都有一

个主线程,但可以建立另外的线程。进程中的线程是并行执行的,各线程占用CPU的时间

由系统决定。

线程是Windows9X/NT系统调度分配CPU时间的基本单位。进程至少有一个线程,

也可以另外增加线程。系统为每个线程分配一个CPU时间片(约20ms),系统不停地在各

个线程之间切换。线程只有在分配的时间片内才有对CPU的控制权。

1、核心对象

核心对象是系统的种资源,系统对象一但产生,任何应用程序都可以开启并使用该对

象。系统给予核心对象一个计数值作为管理之用。

核心对象包括下列几种:

核心对象产生方法

Event(事件)CreateEvent

Mutex(互斥)CreateMutex

Semaphore(信号量)CreateSemaphore

File(文件)CreateFile

File-mapping(文件映射)CreateFi1eMapping

Process(进程)CreateProcess

Thread(线程)CreateThread

这些核心对象的产生方式(使用的API)不同,但都会获得一个handle作为识别;每被

使用一次,其对应的计数值就增1。

核心对象的结束方式相当一致,调用CloseHandle即可。

Process对象不是用来执行程序代码的;它只是一个数据结构,系统用它来管理进程。

程序代码的执行是线程的工作。

2、进程的产生和死亡

执行一个程序,必然会产生一个进程(process)»最直接的程序执行方式就是在shell(如

Windows9X的资源管理器)中用鼠标双击某一个可执行文件图标(如

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论