GDI编程与动态链接库

来源:互联网 发布:编程培训班多少钱 编辑:程序博客网 时间:2024/06/03 19:46
1、GDI(图形设备接口)

     Windows应用程序不支持标准输出函数(如printf),应用程序输出包括文字在内的所有数据都是以图形方式“绘制”到窗口上。
Windows通过图形设备接口GDI对图形输出进行支持。GDI由函数和相关数据类型、宏定义以及结构体组成。主要有:获取和释放设备描述表函数、获取设备信息函数、使用GDI绘图对象函数、绘图函数、设置和获取设备参数函数等,其显示的图形类型有:直线、、曲线、填充、位图、文本等。
     Windows对图形显示设备进行了封装,形成了一个统一的虚拟图形显示设备。应用程序可以在这个虚拟设备上进行绘图,而虚拟设备图形转换为物理设备图形的任务则由设备驱动程序完成。这个虚拟图形设备用一个包含各种设备属性的数据结构来表示,称为设备场镜DC(device content),又称设备上下文。我们也可以这样理解,从应用程序的角度来看,设备场镜DC就是Windows提供的一个“画板”,程序在其上进行绘图。
     当程序员希望在图形输出设备上绘图时,必须先获取设备场镜句柄,然后以此为参数调用GDI函数绘图。Windows给我们提供了几种获取设备场镜句柄的方法。若在处理消息时获取了设备场镜句柄,那么久应该在退出窗口过程WndProc之前释放它。并且DC句柄一旦释放之后就不能再使用了,而必须重新获取。
     几种获取设备场镜句柄的方法:
     a.在处理WM_PAINT消息时,使用BeginPaint和EndPaint调用;
     b.使用GetDC函数获取客户区是设备场镜句柄,使用ReleaseDC释放句柄,绘图结果将在下次WM_PAINT消息刷新后消失;
     c.使用GetWindowDC函数获取整个窗口的设备场镜句柄,调用ReleaseDC释放该句柄;
     d.使用CreateDC函数获取设备场镜句柄,使用DeleteDC释放句柄,该函数更为通用;
     e.使用CreateCompatibleDC创建内存设备场镜句柄,使用DeleteDC释放句柄,在该句柄上绘制的图形不会显示,只是在内存中“绘图”,故而一般需要调用GDI位图函数将它复制到可显示DC句柄上才能看到绘图。

     常用GDI绘图对象有一下几种:
     a.画笔(Pen)
     b.画刷(Brush)
     c.字体(Font)
     d.调色板(Palette)
     e.裁剪区(Region)
     f.位图(BitMap)
     而我们在使用GDI绘图对象时必须按一下步骤:
     a.创建绘图对象或调用GetStockObject获取预定义绘图对象;
     b.调用SelectObject将绘图对象选进设备场镜DC中;
     c.调用DeleteObject删除绘图对象(GetStockObject获取的对象除外)。
     创建和删除绘图对象一般有两个时机:一个时机是在WM_CREATE消息处理中创建绘图对象,在WM_DESTROY消息处理中删除绘图对象,即在窗口建立时创建对象,窗口销毁时删除对象,这样得到的绘图对象在整个窗口运行期间一直有效,优点是不用频繁地创建和删除对象,缺点是绘图对象始终占用内存,存储开销大。另一个时机是在设备场镜句柄有效期间,例如在BeginPaint、GetDC、GetWindowDC、CreateDC、CreateCompatibleDC之后创建绘图对象,在EndPaint、ReleaseDC、DeleteDC之后删除绘图对象。并且Windows规定不能删除设备场镜当前选择的绘图对象。

     双缓冲技术:
     GDI将图形直接绘制在显示设备上时,如果绘制内容较多或是绘制时间较长时,会出现显示闪烁,为解决这一问题,可以采用双缓冲技术。
     双缓冲技术原理:在内存中创建一个与屏幕绘图区域一致的内存DC,然后在其上绘制图形,这样由于闪烁发生在内存中,因此不可见,绘制完成后采用BitBlt快速将图形送到显示设备上,从而可避免显示闪烁。

2、动态链接库

     动态链接库(DLL)是Windows最重要的组成要素之一,大多数与Windows相关的磁盘文件如果不是程序模块,就是动态链接程序。动态链接库是Windows系统中实现共享函数库概念的一种实现方式,其中常见作为DLL实现的文件有:
     a.系统API模块(.dll)文件:如user32.dll、kernel32.dll;
     b.ActiveX控件(.ocx)文件:如Windows上的日历控件;
     c.控制面板(.cpl)文件:控制面板中的每一项都是一个专用的DLL;
     d.设备驱动程序(.drv)文件:如控制打印到打印机的打印机驱动程序。
     动态链接库的主要作用:允许同时运行的若干程序共享一组函数的单一拷贝,不需要重复编译或链接,而一旦装入内存,DLL函数可以被系统中的任何正在运行的应用程序软件所使用,不必再讲DLL函数的另一拷贝装入内存。按照自己的理解就是,在程序运行时动态地将DLL中的函数载入内存,避免重复载入。

自定义DLL:

a.建立DLL工程项目
首先通过向导新建一个Win32项目,项目名称为Win32DLL;
点击下一步,应用程序类型设置为DLL,附加选项设置为空项目,点击完成即可;
在项目中使用快捷键Ctrl+Shift+A,新建cpp文件DLL.cpp以及DLL.h文件。

b.声明导出函数
法一:使用__declspec(dllexport),添加到需要导出的函数前进行声明;
法二:通过模块定义文件(Module-Definition File即.DEF)进行声明。
注:extern “C”的作用是以C方式导出,导出函数默认调用方式是_cdecl,函数的调用方式可在项目属性-配置属性-C/C++-高级-调用约定中进行设置。

c.编写DllMain函数和导出函数
DllMain函数是DLL模块的默认入口点,当Windows加载DLL模块时调用。系统首先调用全局对象的构造函数,然后调用全局函数DllMain,DllMain函数不仅在将DLL链接加载到进程时被调用,在DLL模块与进程分离时亦被调用。

d.编译得到DLL,可使用LordPE工具查看导出函数信息。

DLL的调用:
载入DLL的两种方法:
a.隐式链接:链接到.lib文件并将.dll文件置入新项目的路径中。因此,我们需要创建一个新的默认Win32控制台项目并添加一个源文件,将自定义DLL拷贝到新项目相同的目录下。如:
#include  “../Win32Dll/Dll.h”
#pragma  comment(lib,“../Debug/Win32Dll.lib”)
...
b.显式链接
属于动态加载DLL,需要函数指针和一些Windows函数。与隐式链接不同,显式链接载入DLL时,不需要DLL中的.lib或头文件,而只需要DLL。如:
#include “stdafx.h”
#include  <windows.h>
int _tmain(int argc,_TCHAR* argv[ ])
{
     // 1. 定义要调用的函数指针
     typedef  void(*Fun)( );
     // 2. 获取DLL的实例句柄
     HINSTANCE hInst = LoadLibrary(L“../Debug/Win32Dll.dll“);
     // 3. 得到DLL中的函数地址
     Fun pMsg = (Fun)GetProcAddress(hInst,”Msg“);
     // 4. 使用函数
     pMsg( );
     // 5. 释放DLL
     FreeLibrary(hInst);
     return 0;
}

应用程序查找DLL
     若应用程序使用LoadLibrary进行显示链接,那么在该函数的参数中可以指定DLL文件的完整路径,如果不指定路径或是进行隐式链接,Windows将按照下面的搜索顺序来定义DLL:
a.包含EXE文件的目录;
b.进程的当前工作目录;
c.Windows系统目录;
d.Windows目录;
e.Path环境变量中的一系列目录。

DLL的调试:
a.若动态链接库是自己编写的,并且测试代码也是自己编写的,此时我们可将动态链接库和测试代码的工程建立在一起,在调试测试代码时,可直接调试动态链接库中的代码;
b.若动态链接库是自己编写的,而测试代码不是自己编写的,此时我们需要设置动态链接库中的项目属性,启动调用动态链接库的程序,形成连接之后,在调试的时候才可顺利在动态链接库中调试;
c.若动态链接库和测试代码都不是自己编写的,此时只能通过OllyDbg或其他调试工具进行调试。使用OllyDbg调试DLL,需保证OllyDbg目录下有loaddll.exe文件。

3、静态库

     静态库将函数和数据编译进一个二进制文件,通常命名为*.lib,编译器在链接过程中将这些二进制数据复制出来,并与调用库的其他模块数据组合在一起,形成最终的可执行文件,以后运行该可执行文件时,就不需要这个静态库的支持了。
建立静态库工程:
a.在DLL的基础上修改工程属性中的配置类型位静态库即可;
b.通过向导建立静态库,生成选择应用程序类型位静态库即可。
编写代码:
当我们通过向导新建Win32Lib项目,此时我们需要在新项目中建立头文件lib.h,源文件lib.cpp,编译即可。
使用静态库:只能是隐式链接
#include  ”stdafx.h“
#include ”../Win32lib/lib.h“
#pragma  comment(lib,”../Debug/Win32lib.lib“)
#include ”windows.h“
int  _tmain(int  argc,_TCHAR* argv[ ])
{
Msg( );
return 0;
}
     
0 0
原创粉丝点击