9.1.1 图像处理 1. 常用图像控件 1) Visual C++的Picture控件 9.1.1 图像处理 1. 常用图像控件 1) Visual C++的Picture控件 静态图片(Picture)控件是Visual C++中颇具微词的一个控件,它不像VB中的Image控件可以显示出绝大多数的图像文件(BMP、GIF、JPEG等)而只显示出在资源中的图标、位图、光标以及图元文件的内容。 2) Microsoft Forms 2.0 Image控件 作为弥补,Microsoft Windows提供Microsoft Forms 2.0 Image控件来试图缓和上述的局面。 3) Microsoft Web浏览器 Web浏览器又称为Web客户程序。它是一种用于获取Internet网上资源的应用程序,是查看WWW(万维网)中超文本文档(也包括图像及多媒体)的重要工具。
9.1.1 图像处理 2. BMP图像显示及处理 如果不使用控件,也可以通过Windows API相关函数将一个外部BMP文件图像显示出来,并可通过读写像素将图像进行拉普拉斯锐化处理。所谓“锐化”,是在增强图像边缘效果的同时增加了图像的噪声。
9.1.2 使用媒体控制接口(MCI) MCI设备类型 2. MCI编程步骤 mciSendCommand函数原型如下: 说 明 animation 动画设备 scanner 图形扫描设备 cdaudio CD音频设备 sequencer MIDI设备 dat 数字音频磁带机 vcr 录相机设备 digitalvideo 数字视频设备 videodisc 影碟播放设备 other 未定义的MCI设备 waveaudio 波形音频设备 overlay 窗口中的模拟设备 2. MCI编程步骤 mciSendCommand函数原型如下: MCIERROR mciSendCommand( MCIDEVICEID IDDevice, UINT uMsg, DWORD fdwCommand, DWORD dwParam );
9.1.2 使用媒体控制接口(MCI) 3. 示例 添加的控件 ID号 标 题 其他属性 静态文本控件 IDC_DISPFILE 标 题 其他属性 静态文本控件 IDC_DISPFILE 水平对齐、中垂直、下沉,其余默认 按钮 IDC_FILE 波形文件 默认 IDC_PLAY 播放 IDC_STOP 停止
9.1.2 使用媒体控制接口(MCI) 控 件 变 量 Ex_Wave运行结果 控件ID号 变量类别 变量类型 变量名 范围和大小 IDC_DISPFILE Value CString m_strFileName IDC_FILE Control CButton m_btnFile —— IDC_PLAY m_btnPlay IDC_STOP m_btnStop Ex_Wave运行结果
9.1.3 使用MCIWnd窗口类 1. MCIWnd窗口类 2. 使用MCIWnd窗口类一般步骤 #pragma comment (lib,"vfw32.lib") 2. 使用MCIWnd窗口类一般步骤 (1)在程序中调用MCIWndRegisterClass函数注册MCI窗口类,以便以后用CreateWindow或CreateWindowEx函数创建窗口,或者直接调用函数MCIWndCreate创建窗口。 (2) 获得相应的窗口句柄后,就可调用MCIWndOpen宏来打开设备。 (3) 由于MCIWnd窗口提供了相应的媒体控制按钮,因而不需要用户编写额外的代码。 (4) 作为技巧,用户还应该跟踪MCIWnd窗口的一些消息来调整MCIWnd窗口。
9.1.4 使用OpenGL OpenGL特点及功能 2.OpenGL图形库 科学计算可视化、计算机动画和虚拟现实是当前计算机图形学的三个热点,而这三个热点的核心都是三维真实感图形的绘制。 OpenGL特点及功能 建模功能 (2) 变换功能 (3) 颜色模式设置 (4) 光照和材质设置 (5) 纹理映射 (6) 位图显示和图像增强 (7) 双缓存动画 2.OpenGL图形库 OpenGL图形库一共有几百个函数,主要由核心库、实用库和辅助库三个部分组成。
9.1.4 使用OpenGL 3. 用MFC编写OpenGL程序 (1) 先设置设备环境DC的位图格式(PIXELFORMAT)属性,通过填写一个PIXELFORMATDESCRIPTOR的结构来完成,该结构决定了OpenGL作图的物理设备的属性,比如该结构中的数据项dwFlags中PFD_DOUBLEBUFFER位,如果没有设置,通过该设备的DC作图的OpenGL命令就不可能使用双缓冲来做动画。 (2) 根据刚才的设备环境DC用wglCreateContext建立一个渲染环境RC(Rendering Context,RC),并调用wglMakeCurrent使得RC与DC建立联系。 (3) 调用OpenGL函数作图。 (4)作图完毕以后,先通过设置当前RC为NULL,断开和该渲染环境的联系,然后再根据RC句柄的有效性进行释放或者删除。 4. OpenGL程序示例
9.1.4 使用OpenGL Ex_OpenGL运行结果
9.1.5 DirectX编程 1. DirextX概述 DirectX是Microsoft开发的基于Windows平台的一组API,它是为高速的实时动画渲染、交互式音乐和环境音效等高要求应用开发服务的。 2. Direct3D编程 (1) 用MFC AppWizard(exe)创建一个默认的单文档应用程序Ex_D3D (2)为CEx_D3DView类添加两个保护型对象,如下面的代码: protected: LPDIR m_pD3D // Direct3D对象的接口指针 LPDIRECT3DDEVICE m_pDevice // 设备对象的接口指针
9.1.5 DirectX编程 (3) 用MFC ClassWizard为CEx_D3DView类添加OnInitialUpdate函数的重载,并添加下列Direct3D初始化代码: void CEx_D3DView::OnInitialUpdate() { CView::OnInitialUpdate(); // 创建Direct3D对象,并获取接口IDirect3D9的指针, // 将通过该指针操作Direct3D对象。 m_pD3D = ::Direct3DCreate9(D3D_SDK_VERSION); D3DPRESENT_PARAMETERS d3dpp; ::ZeroMemory(&d3dpp, sizeof(d3dpp)); d3dpp.Windowed = TRUE; // 创建窗口模式的Direct3D程序 d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; d3dpp.BackBufferFormat = D3DFMT_UNKNOWN; // 调用方法IDirect3D9::CreateDevice创建设备对象,并获取 // 接口IDirect3DDevice9的指针,将通过该指针操作设备对象 m_pD3D->CreateDevice( D3DADAPTER_DEFAULT, // 使用缺省的显卡 D3DDEVTYPE_HAL, // 指定设备类型为HAL m_hWnd, // Direct3D窗口的句柄 D3DCREATE_SOFTWARE_VERTEXPROCESSING,//软件顶点处理 &d3dpp, &m_pDevice); }
9.1.5 DirectX编程 (4) 用MFC ClassWizard为CEx_D3DView类添加WM_DESTROY消息映射,并添加下列Direct3D对象指针释放代码: (5) 打开stdafx.h文件,添加Direct3D的头文件包含和库: (6) 在CEx_D3DView::OnDraw函数中添加下列绘制代码: (7) 编译并运行
9.1.5 DirectX编程 (8) 在Direct3D中,所有的三维实体都是由三角形构成的。对于三角形的顶点格式,Direct3D采用了一种被称之为“可变形顶点格式Flexible Vertex Format(FVF)”的技术。 打开Ex_D3DView.h文件,在class CEx_D3DView前面添加下列代码: // 定义FVF的顶点结构 struct CUSTOMVERTEX { float x, y, z; //顶点坐标 DWORD color; //顶点颜色 }; //定义FVF用到的数据项:坐标颜色 #define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ | D3DFVF_DIFFUSE) class CEx_D3DView : public CView …
9.1.5 DirectX编程 (9) 在CEx_D3DView类定义一个用于顶点缓存区的的接口指针对象及构造三角形的函数InitGeometry,如下面的代码: protected: LPDIRECT3D9 m_pD3D; // Direct3D对象的接口指针 LPDIRECT3DDEVICE9 m_pDevice; // 设备对象的接口指针 LPDIRECT3DVERTEXBUFFER9 m_pVB; // 顶点缓存区的的接口指针 void InitGeometry(); (10) 在CEx_D3DView::InitGeometry函数中添加代码: (11) 在CEx_D3DView::OnDestroy函数中添加代码: (12) 在CEx_D3DView::OnDraw函数中添加代码:
9.1.5 DirectX编程 (13) 编译并运行,结果如图所示。
9.1.5 DirectX编程 (14)上述显示的结果是一个黑色的三角形,要想显示出其颜色,还需要在CEx_D3DView:: OnInitialUpdate函数中添加下列代码: void CEx_D3DView::OnInitialUpdate() { … // 因为使用顶点颜色渲染,所以要禁用光照处理 m_pDevice->SetRenderState( D3DRS_LIGHTING, FALSE ); // 关闭“挑选”功能,允许渲染背面 m_pDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_NONE ); }
9.1.5 DirectX编程 (15) 再次编译并运行,最后的结果如图所示
9.1.5 DirectX编程 3. 使用DirectX向导
9.1.5 DirectX编程 Ex_DirectX运行结果
9.2.1 DLL的概念 DLL是建立在客户/服务器通信的概念上,包含若干函数、类或资源的库文件,函数和数据被存储在一个DLL(服务器)上并由一个或多个客户导出而使用,这些客户可以是应用程序或者是其它的DLL。DLL库不同于静态库,在静态库情况下,函数和数据被编译进一个二进制文件(通常扩展名为*.LIB),Visual C++的编译器在处理程序代码时将从静态库中恢复这些函数和数据并把他们和应用程序中的其他模块组合在一起生成可执行文件。这个过程称为“静态链接”,此时因为应用程序所需的全部内容都是从库中复制了出来,所以静态库本身并不需要与可执行文件一起发行。
9.2.2 动态链接库的创建 在Visual C++ 6.0开发环境中,使用应用程序向导中的Win32 Dynamic-Link Library可以创建非MFC动态库,使用MFC AppWizard(dll)可以创建常规DLL和扩展DLL。
9.2.3 动态链接库的访问 (1)用MFC AppWizard创建一个默认的单文档应用程序Ex_USEDLL,但在向导的第5步MFC库设为使用静态链接库,如图所示。 (2) 将Ex_DLL工程中的Debug目录中的Ex_DLL.dll、Ex_DLL.lib两个文件复制到Ex_USEDLL工程目录中。
9.3.1 创建ActiveX控件 1.创建一个ActiveX控件程序 选择“文件”“新建”菜单,在弹出的“新建”对话框中选择“工程”标签,这时显示出一系列的应用程序项目类型。选择MFC AppWizard(dll)的项目类型,在工程框中输入项目名Ex_OCX,结果如图所示。
9.3.1 创建ActiveX控件 向导第2步对话框 向导第1步对话框
9.3.1 创建ActiveX控件 创 建 的 程 序 框 架
9.3.1 创建ActiveX控件 3. 属性的添加 按Ctrl+W快捷键,打开MFC ClassWizard对话框。单击[Add Property](添加属性)按钮,弹出如图所示的对话框。
9.3.1 创建ActiveX控件 4. 属性表的建立 打开Ex_OCXCtl.cpp文件,在靠前的部分中可以看到下面的代码: BEGIN_PROPPAGEIDS(CEx_OCXCtrl, 1) PROPPAGEID(CEx_OCXPropPage::guid) END_PROPPAGEIDS(CEx_OCXCtrl) (2) 为库存属性ForeColor建立属性页,如下面的代码。 BEGIN_PROPPAGEIDS(CEx_OCXCtrl, 2) PROPPAGEID(CEx_OCXPropPage::guid) PROPPAGEID(CLSID_CColorPropPage) END_PROPPAGEIDS(CEx_OCXCtrl)
9.3.1 创建ActiveX控件 (3)将项目工作区切换到“ResourceView”页面,打开IDD_PROPPAGE_EX_OCX对话框资源,将其字体设置为“宋体,9号”,并添加如图所示的控件,取默认的ID号. (4)按Ctrl+W快捷键,打开MFC ClassWizard对话框,切换到“Member Variables”页面,选择类名为CEx_OCXPropPage,双击控件ID号,按表所示为控件添加相关联的变量,是设置IDC_EDIT1控件与nHatch属性相关联的变量时的对话框。
9.3.1 创建ActiveX控件 (5) 将MFC ClassWizard对话框切换到“Message Maps”页面,为CEx_OCXPropPage类添加WM_INITDIALOG消息映射,并添加下列代码 ︰ BOOL CEx_OCXPropPage::OnInitDialog() { COlePropertyPage::OnInitDialog(); m_Spin.SetRange(0, 5); return TRUE; // return TRUE unless you set the focus to a control }
9.3.1 创建ActiveX控件 5. 事件的添加 用MFC ClassWizard可以方便地进行ActiveX控件的事件的添加
9.3.2 测试和使用ActiveX控件 使用ActiveX Control Text Container 测试属性和方法 属性对话框
9.3.2 测试和使用ActiveX控件 2. 在Visual C++程序中使用
9.4.1 进程和线程 进程是应用程序的执行实例,每个进程是由私有的虚拟地址空间、代码、数据和其它系统资源组成。进程在运行时创建的资源随着进程的终止而死亡。线程是一个独立的执行流,是进程内部的一个独立的执行单元,相当于一个子程序,它对应Visual C++中的CWinThread类的对象。单独一个执行程序运行时,默认运行包含一个主线程,主线程以函数地址的形式提供程序的启动点,如main或WinMain函数。当主线程终止时,进程也随之终止,但根据需要,应用程序又可以分解成许多独立执行的线程,每个线程并行的运行在同一进程中。
9.4.2 线程的管理和操作 1. 线程的启动 创建一个用户界面线程,首先要从CWinThread类产生一个派生类,同时必须使用DECLARE_DYNCREATE和IMPLEMENT_DYNCREATE来声明和实现该CWinThread派生类。 第二步是根据需要重载该派生类的一些成员函数,如ExitInstance、InitInstance、OnIdle、PreTranslateMessage等函数,最后启动该用户界面线程,调用其中一个版本的AfxBeginThread函数,如下面的函数原型: CWinThread* AfxBeginThread( CRuntimeClass* pThreadClass, int nPriority = THREAD_PRIORITY_NORMAL, UINT nStackSize = 0, DWORD dwCreateFlags = 0, LPSECURITY_ATTRIBUTES lpSecurityAttrs = NULL );
9.4.2 线程的管理和操作 2. 线程的优先级 3. 线程的悬挂和恢复 4. 终止线程 9.4.2 线程的管理和操作 2. 线程的优先级 CWinThread类中有以下两个成员函数用于线程优先级的操作: int GetThreadPriority(); BOOL SetThradPriority(int nPriority); 3. 线程的悬挂和恢复 CWinThread类中,成员函数SuspendThread用来悬挂线程,暂停线程的执行,ResumeThread用来恢复线程的执行。 4. 终止线程 终止线程有三种途径:一是可以在线程自身内部调用AfxEndThread来终止自身的运行;二是可以在线程的外部调用TerminateThread来强行终止一个线程的运行,然后调用CloseHandle函数释放线程所占用的堆栈;第三种方法是改变全局变量,使线程的执行函数返回,则该线程终止。
9.4.3 线 程 通 信 利用用户定义的消息通信 (1) 用MFC AppWizard(exe)创建一个默认的单文档应用程序Ex_Thread。 (2) 用MFC ClassWizard为CEx_ThreadView类添加OnInitialUpdate的重载,并添加下列代码: BOOL bEnd = FALSE; // 定义的全局变量,用于控制线程的运行 CWinThread *pThread; HWND hWnd; UINT MyThreadFunc(LPVOID pParam) // 线程函数 { while(!bEnd){ Beep(100,100); Sleep(1000); } return 0;} void CEx_ThreadView::OnInitialUpdate() hWnd = GetSafeHwnd(); pThread = AfxBeginThread(MyThreadFunc, hWnd); // 启动线程 pThread->m_bAutoDelete = FALSE; // 线程设为手动删除 CView::OnInitialUpdate();
(3) 用MFC ClassWizard为CEx_ThreadView类添加WM_DESTROY消息映射并添加下列代码: 9.4.3 线 程 通 信 (3) 用MFC ClassWizard为CEx_ThreadView类添加WM_DESTROY消息映射并添加下列代码: void CEx_ThreadView::OnDestroy() { bEnd = TRUE; // 改变变量,线程结束 WaitForSingleObject(pThread->m_hThread, INFINITE); // 等待线程结束 delete pThread; //删除线程 CView::OnDestroy(); } (4) 开Ex_ThreadView.h文件,在class CEx_ThreadView语句前面添加用户消息的定义代码: #define WM_USERMSG WM_USER + 200 lass CEx_ThreadView : public CView {…}
9.4.3 线 程 通 信 (5) 打开Ex_ThreadView.cpp,找到映射消息的入口,添加代码 9.4.3 线 程 通 信 (5) 打开Ex_ThreadView.cpp,找到映射消息的入口,添加代码 (6) 在头文件Ex_ThreadView.h的消息声明处添加代码 (7) 在Ex_ThreadView.cpp文件的后面添加OnUserMessage函数的实现代码 (8) 在MyThreadFunc函数中添加下列代码: UINT MyThreadFunc(LPVOID pParam) // 线程函数 { while(!bEnd){ Beep(100,100); Sleep(1000); } ::PostMessage(hWnd, WM_USERMSG, 0, 0);// 发出用户消息 return 0;
9.4.3 线 程 通 信 (9) 用MFC ClassWizard为CEx_ThreadView类添加WM_LBUTTONDOWN消息映射,并添加下列代码: void CEx_ThreadView::OnLButtonDown(UINT nFlags, CPoint point) { bEnd = TRUE; CView::OnLButtonDown(nFlags, point); } (10) 编译运行。在视图客户区单击鼠标后,稍后就会出现一个消息对话框。
9.4.3 线 程 通 信 2. 用事件对象实现通信 修改CEx_ThreadView::OnInitialUpdate函数代码: 9.4.3 线 程 通 信 2. 用事件对象实现通信 修改CEx_ThreadView::OnInitialUpdate函数代码: void CEx_ThreadView::OnInitialUpdate() { hWnd = GetSafeHwnd(); eStart.SetEvent(); // teStart事件有信号 pThread = AfxBeginThread(MyThreadFunc, hWnd); // 启动线程 pThread->m_bAutoDelete = FALSE; // 线程设为手动删除 CView::OnInitialUpdate(); }
9.4.4 线程同步 1. 临界区 临界区是保证在某一个时间内只有一个线程可以访问数据的方法。临界区被释放后,另外的线程可以强占这个临界区,以便访问共享的数据。 2. 互斥 互斥与临界区很相似,但是使用时相对复杂一些。它不仅可以在同一应用程序的线程间实现同步,还可以在不同的进程间实现同步,从而实现资源的安全共享。 3. 信号量 信号量的用法和互斥的用法很相似,不同的是它可以同一时刻允许多个线程访问同一个资源。
9.5.1 概 述 1. Socket支持 2. WinInet支持 3. MAPI支持 4. ISAPI支持 9.5.1 概 述 1. Socket支持 Socket是一种网络编程接口,最初仅适用于UNIX操作系统。随Windows操作系统的普及,微软和Sun公司开发的基于Windows操作系统的网络编程接口——Windows Sockets, Windows Sockets编程是Windows网络编程的基础。 2. WinInet支持 使用WinInet编写的Internet客户应用程序可以用Internet协议(如Http、FTP和Gopher)从网络服务器上访问信息。 3. MAPI支持 如果要使开发的应用程序可以创建、操作、传输和存储邮件信息,则必须添加并提供MAPI(Message API)支持。 4. ISAPI支持 ISAPI(Internet Server API)提供了一种简单有效的方法来扩展与ISAPI兼容的WEB服务器。ISAPI服务扩展是一个动态链接库(DLL),可以被HTTP服务器调用和装载。
9.5.2 Windows Sockets 编程 Windows Sockets编程机制 (1) 启动和终止 (2) 异步选择机制 由于Windows Sockets的主要服务是以动态链接库WINSOCK.DLL形式实现的,所以在使用任何其它的Windows Sockets API调用之前, (2) 异步选择机制 Windows程序设计是事件来进行驱动的。异步选择机制正是为了在Windows Sockets编程中提供一种网络事件驱动的程序设计方法。 (3) 异步请求机制 在Windows Sockets中,异步请求函数允许应用程序用异步方式获得请求的信息,如WSAAsyncGetHostByAddr等函数。
9.5.2 Windows Sockets 编程 2. Windows Sockets编程示例
9.5.3 WinInet应用 WinInet是以WinSock为基础,是比Winsock更高层的API,它在编写高性能的客户程序方面远远超过了WinSock。