小甲鱼 发表于 2014-9-23 17:49:28

第016讲:各种获得设备环境句柄的方法(课文解读)

以下解读来自《Windows 程序设计》(第5版 珍藏版)P103~105


设备环境

如果想希望在图形输出设备(诸如屏幕或者打印机)上绘制图形,必须首先获得一个设备环境(即 DC)句柄。将句柄传回给程序时,Windows 就给了你使用设备的权限。接着,在 GDI 函数中将这个句柄作为一个参数,告诉 Windows 你将要在哪个设备上进行绘图。

设备环境包含了许多决定 GDI 函数如何工作的属性。这些属性使得 GDI 函数只需要提供少量的参数(如绘制的起始坐标),而不需要提供 Windows 在设备上显示对象时需要的所有其它信息。例如,调用 TextOut 函数时,你只需要在函数中给出设备环境句柄(hdc)、起始坐标、文字和文字的长度。你不需要指定字体、文字颜色、文字后面的背景色彩以及字符间距,因为这些属性都是设备环境的一部分。当你想改变这些属性之一时,你可以通过调用指定函数来实现,此后针对该设备环境的 TextOut 函数就会使用改变后的新属性。

小甲鱼解读:这其实很好理解,设备环境句柄(hdc)其实就是一张通行证,这张通行证上有该设备的信息(DC),有了它,你才被允许使用该设备。


获取设备环境句柄

Windows 提供了几种取得设备内容句柄的方法。如果在处理一个消息时取得了设备环境句柄,应该在退出窗口函数之前释放它(或者删除它)。一旦释放了句柄,它就不再有效了。对于打印机设备内容句柄,规则就没有这么严格(我们将在后边的教程中讨论)。


方法一:

最常用的取得并释放设备内容句柄的方法是,在处理 WM_PAINT 消息时,使用 BeginPaint 和 EndPaint 函数:

hdc = BeginPaint(hwnd, &ps);

// 其他代码
   
EndPaint(hwnd, &ps);
涉及的 API 函数:


[*]【API档案】BeginPaint
[*]【API档案】EndPaint
[*]【API档案】PAINTSTRUCT 结构

其中,变量 ps 是一个类型为 PAINTSTRUCT 的结构。这个结构中的字段 hdc 和 BeginPaint 函数返回的设备环境句柄的值相同。PAINTSTRUCT 结构还包含了一个名为 rcPaint 的矩形结构(【API档案】RECT 结构),该结构定义了一个包围窗户区无效范围的矩形。使用从 BeginPaint 函数获取的设备环境句柄,就只能在这个矩区域内绘图。调用 BeginPaint 函数将使这个区域有效。


方法二:

设备环境句柄还可以在处理非 WM_PAINT 消息时由 Windows 程序获取:
hdc = GetDC(hwnd);

// 其他代码

ReleaseDC(hwnd, hdc);
涉及的 API 函数:


[*]【API档案】GetDC
[*]【API档案】ReleaseDC

其中,设备环境指的是窗口句柄为 hwnd 的窗口客户区。调用这些函数和使用 BeginPaint、EndPaint 函数组合的主要差别是从 GetDC 函数返回的句柄可以在整个客户区内绘制。并且,GetDC 和 ReleaseDC 函数并不使任何客户区的无效区域变为有效。


方法三:

Windows 程序还可以获得用于整个窗口的,而不仅仅是窗口客户区的设备环境句柄:

hdc = GetWindowDC(hwnd);

// 其他代码

ReleaseDC(hwnd, hdc);
涉及的 API 函数:


[*]【API档案】GetWindowDC
[*]【API档案】ReleaseDC

这里的设备环境除了包括客户区,还包含窗口标题栏、菜单、滚动条和客户区的外框。应用程序很少使用 GetWindowDC 函数。如果你想尝试使用它,则还应当捕获 WM_NCPAINT(nonclient paint,非客户区绘制)消息,Windows 使用这个消息在窗口的非客户区绘图。


方法四:

调用 BeginPaint、GetDC 和 GetWindowDC 函数可以获得在视频显示器上与一个特定的窗口相关联的设备环境。还有一个更通用的用于获取设备环境句柄的函数是 CreateDC:

hdc = CreateDC(pszDriver, pszDevice, pszOutput, pData);

// 其他代码

DeleteDC(hdc);
涉及的 API 函数:


[*]【API档案】CreateDC
[*]【API档案】DeleteDC

例如,你可以通过调用下面的函数获取当前整个屏幕的设备环境句柄:
hdc = CreateDC(TEXT("DISPLAY"), NULL, NULL, NULL);
在窗口外输出文字或图像不是很好,但是对于一些特殊的应用还是有用的。(虽然在官方文档中并没有提到这种方法,但是你还是可以通过在调用 GetDC 时使用一个 NULL 参数来得到整个屏幕的设备环境。)在后边的教学中,打印机的设备环境句柄就是使用 CreateDC 函数来获取的。


方法五:

有时候,仅需要获取一些关于设备环境的信息,而不需要在上面绘制任何东西。在这些情况下,可以调用 CreateIC 函数获取一个“信息上下文”(Information Context)句柄。这个函数的参数和 CreateDC 函数的参数相同:

hdc = CreateIC(pszDriver, pszDevice, pszOutput, pData);

// 其他代码

DeleteDC(hdc);
涉及的 API 函数:

【API档案】CreateIC
【API档案】DeleteDC

但是,往设备上写东西时,不能使用信息上下文句柄。


方法六:

处理位图时,有时可能会用到一个“内存设备环境”:

hdcMem = CreateCompatibleDC(hdc);

// 其他代码

DeleteDC(hdcMem);
涉及的 API 函数:


[*]【API档案】CreateCompatibleDC
[*]【API档案】DeleteDC

可以把一个位图选入内存设备环境,并且调用 GDI 函数绘制这个位图。我们将在后边的视频中介绍这些技术。


方法七:

前边讲过,图元文件是以二进制形式编码的 GDI 函数调用的集合。它可以通过获取一个图元文件的设备环境来创建:

hdcMeta = CreateMetaFile(pszFilename);

// 其他代码

hmf = CloseMetaFile(hdcMeta);
涉及的 API 函数:


[*]【API档案】CreateMetaFile
[*]【API档案】CloseMetaFile

在图元文件设备环境有效时,使用 hdcMeta 所做的任何 GDI 调用都不会被直接显示出来,它们都会变成图元文件的一部分。当你调用 CloseMetaFile 时,图元文件设备环境句柄变为无效,该函数返回一个图元文件句柄(hmf)。


WinSDK

hslim 发表于 2014-10-23 21:46:51

PAINTSTRUCT 结构还包含了一个名为 rcPaint 的矩形结构(【API档案】RECT 结构),该结构定义了一个包围窗户区无效范围的矩形。使用从 BeginPaint 函数获取的设备环境句柄,就只能在这个矩区域内绘图。调用 BeginPaint 函数将使这个区域有效。

tangxingchen 发表于 2015-2-1 16:44:04

很好的资料

lsk19871987 发表于 2015-10-18 16:19:37

自学的好帮手,好老师, 辛苦了,老师

hustjinghu 发表于 2016-10-23 22:51:10

小甲鱼,你对 设备区域的比方好难哦、好费解哦;给你个更好的比方: 各种不同的DC就好比各种不同的画家,画家要在窗口的客户区作图,画家作图需要各种画笔啦、画刷啦、位图啦。。。,所以,每次作图之前,需要将这些画图工具放到画家(设备句柄)的手里。

alltolove 发表于 2016-11-6 17:15:15

晕,这马多啊!
页: [1]
查看完整版本: 第016讲:各种获得设备环境句柄的方法(课文解读)