windows编程复习纲要.ppt

上传人:tia****nde 文档编号:12707548 上传时间:2020-05-14 格式:PPT 页数:48 大小:743KB
返回 下载 相关 举报
windows编程复习纲要.ppt_第1页
第1页 / 共48页
windows编程复习纲要.ppt_第2页
第2页 / 共48页
windows编程复习纲要.ppt_第3页
第3页 / 共48页
点击查看更多>>
资源描述
2020/5/14,1,前言,什么是WindowsAPI?,有过编程经验的读者都应该知道,在传统应用程序中要完成某个功能,都是以函数调用的形式实现的,同样,Windows应用程序也是以函数调用的方式来通知操作系统执行相应的功能的。,操作系统所能够完成的每一个特殊功能通常都有一个函数与其对应,也就是说,操作系统把它所能够完成的功能以函数的形式提供给应用程序使用,应用程序对这些函数的调用就叫做系统调用,这些函数的集合就是Windows操作系统提供给应用程序编程的接口(ApplicationProgrammingInterface),简称WindowsAPI。,如CreateWindow就是一个API函数,应用程序中调用这个函数,操作系统就会按照该函数提供的参数信息产生一个相应的窗口。这些API函数都在windows.h中声明。,2020/5/14,2,什么是MFC?,MFC英文全称为MicrosoftFoundationClasses(微软基础类库),是把WindowsAPI进行封装的类库,它是一个类的集合,通过覆盖WindowsAPI,为编程提供了一个面向对象的界面。MFC使Windows程序员能够利用C+面象对象的特性进行编程。,前言,2020/5/14,3,为什么要使用MFC?,可重用性封装后使方法和属性更紧密的捆绑常用的功能自动化,减少编写代码的数量提供应用程序的框架结构框架结构提供了抽象功能,它远远超出了WindowsAPI的功能。例如:MFC的文档/视图体系结构在API上建造了一个功能强大的基础结构,它把程序中数据的图形表示(或成为视图)与数据本身分开。这种抽象对API而言完全是陌生的,而且在MFC框架结构之外或类似的类库中也不存在。,前言,2020/5/14,4,Windows程序内部运行机制,Windows编程模型,事件驱动编程模型以消息为基础,事件驱动之,WM_PAINT,WM_KEYDOWN,WM_LBUTTONDOWN,消息响应,消息响应,消息响应,DefWindowProc,来源于操作系统的消息,消息队列,WinMain,消息循环,发送消息,窗口过程,未处理的消息,应用程序,窗口,2020/5/14,5,Windows程序内部运行机制,小小知识点“句柄”,句柄(HANDLE),资源的标识。操作系统要管理和操作这些资源,都是通过句柄来找到对应的资源。按资源的类型,又可将句柄细分成图标句柄(HICON),光标句柄(HCURSOR),窗口句柄(HWND),应用程序实例句柄(HINSTANCE)等等各种类型的句柄。操作系统给每一个窗口指定的一个唯一的标识号即窗口句柄。,2020/5/14,6,Windows程序内部运行机制,编写Windows应用程序的要素,消息响应,消息响应,消息响应,DefWindowProc,WinMain,消息循环,发送消息,窗口过程,未处理的消息,应用程序,1入口函数WinMain2创建窗口3发送消息与消息循环4窗口过程与消息响应,消息,窗口,2020/5/14,7,窗口类第二个成员变量lpfnWndProc指定了这一类型窗口的过程函数,也称回调函数。回调函数的原理是这样的,当应用程序收到给某一窗口的消息时(还记得前面讲过的消息通常与窗口相关的吗?),就应该调用某一函数来处理这条消息。这一调用过程不用应用程序自己来实施,而由操作系统来完成,但是,回调函数本身的代码必须由应用程序自己完成。对于一条消息,操作系统到底调用应用程序中的哪个函数(回调函数)来处理呢?操作系统调用的就是接受消息的窗口所属的类型中的lpfnWndProc成员指定的函数。每一种不同类型的窗口都有自己专用的回调函数,该函数就是通过lpfnWndProc成员指定的。,Windows程序内部运行机制,窗口过程函数,2020/5/14,8,Windows程序内部运行机制,创建窗口,创建一个完整的窗口需要经过下面四个操作步骤:Step1:设计一个窗口类;Step2:注册窗口类;Step3:创建窗口;Step4:显示及更新窗口。,2020/5/14,9,Windows程序内部运行机制,WM_PAINT,Windows把一个最小的需要重绘的正方形区域叫做“无效区域”。当Windows发现了一个“无效区域“后,它就会向该应用程序发送一个WM_PAINT消息,通知应用程序重新绘制窗口。,当窗口从无到有、改变尺寸、最小化后再恢复、被其他窗口遮盖后再显示时,窗口的客户区都将变为无效。,那么,应用程序是如何通知操作系统执行某个功能的呢?,2020/5/14,10,Windows程序内部运行机制,自行发送消息的两种方式,发送消息可以使用SendMessage和PostMessage函数。,SendMessage将消息直接发送给窗口,并调用该窗口过程进行处理。在窗口过程对消息处理完毕后,该函数才返回。,PostMessage函数将消息放入与创建窗口的线程相关联的消息队列后立即返回。,2020/5/14,11,虚函数与多态性,当C+编译器在编译的时候,发现基类的函数是虚函数,这个时候C+就会采用迟绑定(latebinding)的技术,在运行时,依据对象的类型(在示例程序中,我们传递的派生类对象的地址)来确认调用的哪一个函数,这种能力就做C+的多态性。,在基类的函数前加上virtual关键字,该函数则为虚函数。虚函数派生下去仍为虚函数,而且可以省略virtual关键字。在派生类中重写该函数,运行时将会根据指针实际所指的对象的类型来调用相应的函数。如果对象类型是派生类,就调用派生类的函数;如果对象类型是基类,就调用基类的函数。,掌握C+,2020/5/14,12,纯虚函数与抽象类,纯虚函数是指被标明为不具体实现的虚函数。纯虚函数可以让类先具有一个操作名称,而没有操作内容,让派生类在继承时再去具体地给出定义。凡是含有纯虚函数的类叫做抽象类。这种可不能实例化对象,只能作为基类为派生类服务。注意:派生类中必须实现基类的纯虚函数,否则,派生类也变成了抽象类,不能实例化对象。纯虚函数多用在一些方法行为的实际上。在设计基类时,不太好确定或将来的行为多种多样,而此行为又是必需的,我们就可以在基类的设计中,以纯虚函数来声明次中行为,而不具体实现它。,掌握C+,2020/5/14,13,const的使用方法,const成员函数,任何不会修改数据成员的函数都应该声明为const类型。如果在编写const成员函数时,不慎修改了数据成员,或者调用了其它非const成员函数,编译器将指出错误,这无疑会提高程序的健壮性。,2020/5/14,14,类中的Static成员变量与函数,静态成员函数与变量的特性,静态成员函数和静态成员变量属于类本身,在类加载的时候(编译阶段),即为它们分配了空间,因此可以通过类名:函数名或类名:变量名来访问。而非静态函数和非静态成员属于对象的方法和数据,也就是应该首先产生类的对象,然后通过类的对象去引用。静态函数不属于某个具体的对象,也就是说,在还没有产生类的任何一个具体对象时,静态函数就已经存在于程序的代码区了。但这是类的非静态成员还没有分配内存空间,这样,在静态成员函数中是没有办法对类非静态成员进行操作的。因此,在静态成员函数中只能访问静态成员变量,不能访问非静态成员函数和非静态成员变量。非静态成员函数中可以调用静态成员函数。,2020/5/14,15,MFC框架程序剖析,MFC单文档界面程序初探(简答题),test.h、test.cpp,应用程序类:CTestApp(由CWinApp继承而来),每一个MFC程序有且仅有一个主应用程序类对象theApp,它代表一个程序本体,用于管理和维护主应用程序,MainFrm.h、MainFrm.cpp,主框架类CMainFrame(由CWnd继承而来),主框架是应用程序的主体窗口,其他的窗口(如视类窗口、工具条、状态条)都依附于主框架窗口(覆盖在它上面)。,2020/5/14,16,MFC框架程序剖析,MFC单文档界面程序初探(续),testView.h、testView.cpp,视图类:CTestView(由CWnd继承而来),负责管理和维护图形显示操作。,testDoc.h、testDoc.cpp,文档类:CTestDoc(由CDocumet继承而来),负责显示数据的后台管理和维护。,2020/5/14,17,MFC框架程序剖析,MFC中的全局对象theApp,初始化CTestAPP对象,应用程序内存获得配置调用基类CWinApp构造函数(在MFC源码目录的文件中AppCore.cpp),初始化完成程序运行时的一些初始化工作。注意:由于theApp是个全局对象,所以CWinApp构造函数会在入口函数WinMain之前运行。,2020/5/14,18,图形操作,设备描述表DC,在Windows平台下,窗口的所有图形操作都是利用DC来完成的。如果使用GetDC来得到DC的句柄,在完成图形操作后,必须调用ReleaseDC来释放DC所占用的资源,以避免内存泄漏。利用计算机作图,窗口相当于画布,因此,在获取DC的句柄时,总是和一个指定的窗口相关联。,2020/5/14,19,简单绘图,利用CClientDC、CWindowDC类绘图(简答题),CClientDC派生于CDC类,并且在构造时调用GetDC函数,在析构时调用ReleaseDC函数。它与CDC一样,都是实现在窗口的客户区绘图。,CWindowDC派生于CDC类,并且在构造时调用GetWindowDC函数,在析构时调用ReleaseDC函数。该对象可以访问整个窗口区域,包括客户区与非客户区。,2020/5/14,20,简单绘图,绘制彩色线条使用CPen类,CPenpen(PS_SOLID,5,RGB(255,0,0);CClientDCdc(this);CPen*pOldPen=dc.SelectObject(,注意:当构造一个GDI对象后,该对象并不会立即生效,必须通过SelectObject函数选入设备描述表,它才会在以后的绘制操作中生效。在完成绘图操作之后,都要利用SelectObject把先前的GDI对象选入设备描述表,以便使其恢复到先前的状态。,2020/5/14,21,Windows消息的分类,标准消息除WM_COMMAND之外,所有以WM_开头的消息。从CWnd派生的类,都可以接收到这类消息。命令消息来自菜单、加速键或工具栏按钮的消息。这类消息都以WM_COMMAND呈现。在MFC中,通过菜单项的标识(ID)来区分不同的命令消息;在SDK中,通过消息的wParam参数识别。从CCmdTarget派生的类,都可以接收到这类消息。通告消息由控件产生的消息,例如,按钮的单击,列表框的选择等均产生此类消息,为的是向其父窗口(通常是对话框)通知事件的发生。这类消息也是以WM_COMMAND形式呈现。从CCmdTarget派生的类,都可以接收到这类消息。,菜单响应函数,2020/5/14,22,菜单命令消息路由的过程(简答题),当点击某菜单项时,最先接收到这个菜单命令消息的是框架类。框架类把接收到的这个消息传给它的子窗口,即视类。视类根据命令消息映射机制查找自身是否对这个消息进行了响应,如果响应了,则调用自身相应响应函数。如果视类没有对此命令消息作出响应,就交由文档类,文档类同样查找自身是否这个消息进行了响应,如果响应了,则调用自身相应响应函数。如果文档类也未做出响应,就把这个命令消息交还给视类,后者再交还给框架类。框架类查看自己是否对这个命令消息进行了响应,如果它也没有相应,就把这个菜单命令消息交给应用程序类,由后者来处理。,菜单响应函数,2020/5/14,23,对话框,对话框是一个窗口,与对话框资源相关的类为CDialog,由CWnd类派生而来。可以将对话框看成是一个大容器,在它上面能够放置各种标准和扩展控件,是用户与程序进行交互的重要手段。在MFC中,所有的控件都是由CWnd派生而来,因此,控件实际上也是窗口。,对话框基本知识,2020/5/14,24,对话框的种类,模式对话框:当其显示时,程序会暂停执行,直到关闭这个对话框后,才能继续执行程序中其他任务。例如“文件/打开”对话框。无模式对话框:当其显示时,允许转而执行程序中其他任务,而不用关闭这个对话框。该类型对话框不会垄断用户的操作,用户仍可以与其他界面对象进行交互。例如“查找”对话框。,对话框基本知识,2020/5/14,25,DoModal()函数,创建模式对话框需要调用CDialog类的成员函数:DoModal,该函数的功能就是创建并显示一个模式对话框。,创建模式对话框,voidCMainFrame:OnTest()/TODO:AddyourcommandhandlercodehereCMyDialogdlg;dlg.DoModal();,2020/5/14,26,Create()函数,创建非模式对话框需要调用CDialog类的成员函数:BOOLCreate(UINTnIDTemplate,CWnd*pParentWnd=NULL);,创建非模式对话框,voidCMainFrame:OnTest()/TODO:AddyourcommandhandlercodehereCMyDialogdlg;dlg.Create(IDD_DIALOG1,this);,注意:运行程序,对话框并未显示!,2020/5/14,27,ShowWindow()函数,当利用Create函数创建非模式对话框时,还需要调用ShowWindow函数将这个对话框显示出来。,创建非模式对话框,voidCMainFrame:OnTest()CMyDialogdlg;dlg.Create(IDD_DIALOG1,this);dlg.ShowWindow(SW_SHOW);,注意:运行程序,对话框仍未显示!,2020/5/14,28,对话框未显示之原因分析,这里创建的非模式对话框对象(dlg)是一个局部对象,当OnTest函数结束时,dlg这个对象的生命周期也就结束了,它会销毁与之相关联的对话框资源,因此对话框不会显示。,在创建模式对话框时,当执行到DoModal函数显示这个对话框时,程序会暂停执行,直到关闭模式对话框之后,程序才继续执行。也就是说,当模态对话框显示时,dlg这个对象的生命周期并未结束。,为什么模式对话框不会出现这样的问题?,结论:,在创建非模式对话框时,不能把对话框对象定义为局部对象。,创建非模式对话框,2020/5/14,29,解决方法1使用成员变量,把对话框对象定义为视类的成员变量。,注意:在销毁对话框之前,Create函数只能调用一次,否则会出错。,voidCMainFrame:OnTest()staticBOOLbFlag=TRUE;if(TRUE=bFlag)dlg.Create(IDD_DIALOG1,this);bFlag=FALSE;dlg.ShowWindow(SW_SHOW);,创建非模式对话框,2020/5/14,30,解决方法2使用推内存,把对话框对象定义为指针,在堆上分配内存。,voidCMainFrame:OnTest()CMyDialog*pDlg=newCMyDialog;pDlg-Create(IDD_DIALOG1,this);pDlg-ShowWindow(SW_SHOW);,注意:该程序存在问题。由于没有办法释放这个指针变量所指向的那块内存,会出现内存泄漏!,消除内存泄漏的办法:1.指针变量定义成全局变量;或者2.重载对话框的PostNcDestroy函数,添加代码deletethis.,创建非模式对话框,2020/5/14,31,利用GetDlgItem改变控件文本内容,voidCMyDialog:OnNumber1()CStringstr;GetDlgItem(IDC_NUMBER1)-GetWindowText(str);if(str=Number1:)GetDlgItem(IDC_NUMBER1)-SetWindowText(数值1:);elseGetDlgItem(IDC_NUMBER1)-SetWindowText(Number1:);,注意:静态文本框在默认状态下是不发送通告消息的。改变这一默认状态,必须在属性窗口选中Notify这个选项。,访问控件的七种方法,2020/5/14,32,在窗口创建之前更改,更改窗口大小、标题、风格,如果希望在应用程序窗口创建之前修改它的大小、标题和风格,应该在CMainFrame类的PreCreateWindow成员函数进行。,该函数有个类型是CREATESTRUCT结构的参数,如果在修改了这个参数中的成员变量的值,那么这种改变会反映到MFC底层代码中,当MFC底层代码调用CreateWindowEx函数去创建窗口时,它就会使用改变后的参数值去创建这个窗口。,2020/5/14,33,在窗口创建之后更改其风格,在应用程序窗口创建之后修改它的风格属性,可在CMainFrame类的ONCreate函数中调用SetWindowLong函数实现。,SetWindowLong(HWNDhWnd,intnIndex,LONGdwNewLong),该函数的作用是改变制定窗口的属性(包括设置新的窗口风格、设置新的窗口过程、设置新的应用程序实例局柄等)。要改变窗口的风格,则将该函数的第二个参数指定为GWL_STYLE,然后由第三个参数指定新的窗口风格。,更改窗口大小、标题、风格,2020/5/14,34,在窗口创建之后更改,更改光标、标题栏图标、窗口背景,要在应用程序窗口创建之后修改它的光标、图标和背景,可在OnCreate函数中调用SetClassLong函数实现。,SetClassLong(HWNDhWnd,intnIndex,LONGdwNewLong),该函数的作用是:重新设置指定窗口所属窗口类的WNDCLASS结构体中指定数据成员的属性(包括设置新的窗口背景画刷、光标、图标和窗口类样式)。,2020/5/14,35,注意事项,更改光标、标题栏图标、窗口背景,在MFC中,如果要修改应用程序窗口的图标,则应该框架类中进行,因为框架窗口才有标题栏;如果要修改程序窗口的背景和光标,则应该在视类中进行。,2020/5/14,36,程序与进程(简答),进程与线程,程序:计算机指令的集合,它以文件的形式存储在磁盘上。进程:通常被定义为一个正在运行的程序的实例,是一个程序在其自身的地址空间中的一次执行活动。进程是活的,是资源申请、调度和独立运行的单位,因此,它使用系统中的运行资源;而程序是死的,它不占用系统的运行资源。,2020/5/14,37,进程与线程,进程与线程,进程是不活泼的。进程从来不执行任何东西,它只是线程的容器。若要使进程完成某项操作,它必须拥有一个在它的环境中运行的线程,此线程负责执行包含在进程的地址空间中的代码。单个进程可能包含若干个线程,这些线程都“同时”执行进程地址空间中的代码。每个进程至少拥有一个线程,来执行进程的地址空间中的代码。当创建一个进程时,操作系统会自动创建这个进程的第一个线程,称为主线程。此后,该线程可以创建其他的线程。,2020/5/14,38,获得互斥对象所有权,利用互斥对象实现线程同步,线程必须主动请求共享对象的使用权才能获得该所有权,这可以通过调用WaitForSingleObject函数实现。,DWORDWatiForSingleObject(HANDLEhHandle,DWORDdwMillisecond);,HANDLEhHandle所请求对象的句柄。本例为互斥对象句柄:hMutex。一旦互斥对象处于有信号状态,则该函数返回,接着,操作系统会将这个互斥对象设为未通知状态。如果该互斥对象处于无信号状态,则该函数会一直等待,这样会暂停线程的执行。DWORDdwMillisecond指定等待的时间,如果指定的时间间隔已过,即使所请求的对象处于无信号状态,该函数也返回。如果该参数为0,该函数立即返回。如果该参数为INFINTE,则该函数永远等待,直到互斥对象处于由信号状态才返回。,2020/5/14,39,利用互斥对象实现线程同步,#include#includeDWORDWINAPIThreadProc1(LPVOIDlpParameter);DWORDWINAPIThreadProc2(LPVOIDlpParameter);inttickets=1;HANDLEhMutex;voidmain()HANDLEhThread1;HANDLEhThread2;hThread1=CreateThread(NULL,0,ThreadProc1,NULL,0,NULL);hThread2=CreateThread(NULL,0,ThreadProc2,NULL,0,NULL);CloseHandle(hThread1);CloseHandle(hThread2);hMutex=CreateMutex(NULL,FALSE,NULL);Sleep(5000);,火车站售票系统模拟程序,2020/5/14,40,利用互斥对象实现线程同步,/线程1的入口函数(售票窗口1)DWORDWINAPIThreadProc1(LPVOIDlpParameter)while(TRUE)WaitForSingleObject(hMutex,INFINITE);if(tickets=100)Sleep(1);coutthread1sellticket:tickets+endl;elsebreak;ReleaseMutex(hMutex);return0;,火车站售票系统模拟程序,2020/5/14,41,利用互斥对象实现线程同步,/线程2的入口函数(售票窗口2)DWORDWINAPIThreadProc2(LPVOIDlpParameter)while(TRUE)WaitForSingleObject(hMutex,INFINITE);if(tickets=100)Sleep(1);coutthread2sellticket:tickets+endl;elsebreak;ReleaseMutex(hMutex);return0;,火车站售票系统模拟程序,2020/5/14,42,动态链接库概述,微软任何一个版本的Windows操作系统,动态链接库(DLL)都是其核心和基础。动态链接库不能直接运行。它们是一些独立的文件,其中包含能被可执行程序或其它DLL调用来完成某项工作的函数。只有在其它模块调用动态链接库中的函数时,它才发挥作用。WindowsAPI中的所有函数都包含在DLL中。其中有3个最重要的DLL,Kernel32.dll,它包含用于管理内存、进程和线程的各个函数;User32.dll,它包含用于执行用户界面任务(如窗口的创建和消息的传送)的各个函数;GDI32.dll,它包含用于画图和显示文本的各个函数。,Dll概述,2020/5/14,43,动态链接库概述,使用动态链接库的好处(简答),增强程序的扩展性可以采用多种编程语言来写提供二次开发的平台简化项目管理节省磁盘空间和内存有助于资源共享,2020/5/14,44,Win32DLL的创建,导出DLL中的函数,注意:应用程序如果想要访问DLL中的函数,那么该函数必须是已经被导出的函数。,为了让DLL导出函数,需要在每一个将要被导出的函数前添加标识符:_declspec(dllexport)。,_declspec(dllexport)intadd(inta,intb)returna+b;_declspec(dllexport)intsubtract(inta,intb)returna-b;,Build后,在Debug目录下会产生一个动态库Dll1.dll文件和一个引入库文件Dll1.lib。,2020/5/14,45,Win32DLL的创建,导出DLL中的类,在动态链接库中,除了函数能被导出,C+类同样也能够被导出。,为了让DLL导出类,在DLL中定义类时,需要在class关键字和类名之间加入标识符:_declspec(dllexport)。,注意:在访问导出类的函数时,仍受限于函数自身的访问权限。也就是说,如果该类的某个函数访问权限不是Pubilc,那么外部程序仍无法访问这个函数。,另外,在实现动态链接库时,可以不导出整个类,而只导出该类中的某些成员函数。具体做法是将标识符添加到成员函数前。,2020/5/14,46,隐式链接方式加载DLL,以上程序能够成功通过编译,但在程序链接时会产生三个错误,因为此时链接器不知道这两个函数是在哪个地方实现的。为了解决这个问题,就需要利用动态链接库的引入库文件。引入库文件并没有包含实际的代码,它是用来为链接程序提供必要的信息,以便在可执行文件中建立动态链接时需要用到的重定位表。,使用引入库文件,加载引入库文件的两种方法(加载之前先把dll1.lib复制到dlltest工程目录中):选择“projectSettings”命令,选择link选项卡,在“Object/librarymodules”选项编辑框中输入:dll1.lib通过“addfilestoproject”直接将dll1.lib加入到工程中。,2020/5/14,47,显式加载方式加载DLL,名字改编问题,如果希望动态链接库在编译时,导出函数的名称不要发生改变,在定义导出函数时,需要加上限定符:extern“C”,externC_declspec(dllexport)intadd(inta,intb)returna+b;externC_declspec(dllexport)intsubtract(inta,intb)returna-b;,extern“C”可以解决C+对C语言之间的函数名改编问题,但这种方法有一个缺陷,就是不能用于导出一个类的成员函数,只能用于导出全局函数这种情况。,2020/5/14,48,DllMain函数,DllMain函数介绍,一个Win32程序,对可执行模块来说,其入口函数是WinMain;而对DLL来说,其入口函数是DllMain,该函数是可选的。也就是说,在编写DLL程序时,可以提供也可以不提供DllMain函数。,注意:如果提供了DllMain函数,那么在此函数中不要进行太复杂的调用。因为在加载该动态链接库时,user32.dll或GDI32.dll等一些Windows核心DLL还没有加载,这时会导致程序终止。,
展开阅读全文
相关资源
相关搜索

当前位置:首页 > 图纸专区 > 课件教案


copyright@ 2023-2025  zhuangpeitu.com 装配图网版权所有   联系电话:18123376007

备案号:ICP2024067431-1 川公网安备51140202000466号


本站为文档C2C交易模式,即用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知装配图网,我们立即给予删除!