|
3 C' y( \$ }* ]作者:罗隽( O* D8 \& d6 I0 R% n( u
5 O+ ^) J9 U2 Z |
' [- n. G/ E& o6 @" B
5 {, Q1 G9 e. v$ k* W2 E Microsoft的针对与设备无关位图(DIB位图),在其WIN32 SDK的Multimedia中提供了一组绘制DIB位图的高性能函数组──DrawDib函数组。DrawDib函数组是一组不依赖于图形设备接口(GDI)函数,而直接操作显存的函数组。它们支持8位、16位、24位和32位图象深度的DIB。总的来说,DrawDib函数组类似于StretchDIBits函数,它们都提供了将图象拉伸和抖动的功能,然而,DrawDib函数组还支持图象的解压、数据流以及更多的显示适配器。在某些情况下,DrawDib函数组还具有更大的优越性。但是,在某些场合下,DrawDib函数组却不能取代StretchDIBits函数。下面就DrawDib函数组和StretchDIBits函数使用的场合加以区别和说明: 3 }' {8 r" q4 b: E3 e
颜色信息表格式。DrawDib函数组只支持颜色信息表格式为DIB_RGB_COLORS格式的图象,如果要显示以DIB_PAL_COLORS或DIB_PAL_INDICES格式的图象,则必须用StretchDIBits函数。
3 ?8 }% D& }6 l6 w光栅操作模式。DrawDib函数组只能使用SRCCOPY光栅操作模式,如果要求不仅仅使用SRCCOPY模式的话,只能用StretchDIBits函数。同样地,如果要使用其他光栅操作,例如XOR,只能用StretchDIBits函数。
5 s) Q2 @7 r7 e$ d" x视频及动画回放的质量。DrawDib函数组支持数据流应用,诸如视频片和动画序列,它比StretchDIBits函数提供了更高的图象质量以及对回放过程的改进。
+ v/ L8 w1 a6 d& M7 O; ~0 e' f显示适配器。DrawDib函数组比StretchDIBits函数支持更多的显示适配器。DrawDib函数组支持使用4位图象深度提供16色调色板的VGA适配器,使用8位图象深度提供256色调色板的SVGA适配器和使用16位、24位和32位图象深度提供成千上万种颜色的真彩色适配器。DrawDib函数组还使用了受限制的潜在能力提高了图象在显示适配器上的速度和质量。例如,当使用8位的显示适配器时,DrawDib函数组有效地将真彩色图象抖动为256色;同样的,使用4位的显示适配器时,它们也将8位深度的图象抖动成4位。 ) B4 w& h- r1 x# x+ V: p
图象拉伸。正如StretchDIBits一样,DrawDib函数组用源矩形和目的矩形来控制一个图象显示的部分。可以通过改变源矩形和目的矩形的位置和大小来裁剪一幅图象不需要的部分和拉伸某部分。如果显示驱动不支持图象拉伸,那么DrawDib函数组提供了比StretchDIBits函数更有效的拉伸能力。
! C* F r( t+ D* D9 o" s压缩图象。DrawDib函数组支持好几种压缩和解压方法,其中包括游程编码,JPEG,Cinepak,411YUV和Indeo?。 * P+ K* f2 g" T7 W, H# P
! B- F5 w0 d# H& K4 C) \/ e$ W
DrawDib的操作
8 h2 ?, _$ g, i/ m" Y4 H' g/ A 通过使用DrawDibOpen函数初始化DrawDib函数组。DrawDibOpen负责装载动态连接库(DLL),申请内存资源,DrawDib设备环境(DC),并且维持初始化相关的设备环境计数。DrawDibOpen同时返回一个其它DrawDib函数所需要使用的新的DC句柄。 + E6 q0 `) h u# o; s
当使用完DrawDib DC后,可以用DrawDibClose函数释放它。DrawDibClose同时减少存取DLL的应用的计数。在应用程序中,DrawDibClose函数应是最后的DrawDib操作。
9 J( R1 H4 `3 U7 ^8 ~- X 可以创建任意多的DrawDib DC,也可以同时使用多个DrawDib DC来绘制几幅位图。在应用程序中可以创建多个不同性质的DrawDib DC,这样就可以选择最合适的DC设置。例如,在同一应用程序中,创建两个不同的DrawDib DC,一个用来显示图象的正常分辨率,另一个用来显示图象的放大部分。
* A& I, h, k7 T/ \ E 为了更有效地运行,DrawDib函数组需要知道显示适配器及其驱动的信息。显示配置信息是在第一次使用包含DrawDib函数组的DLL时,对显示适配器通过了一系列的测试之后得到的。DrawDib函数组的所有应用都要用到这个配置信息。可以通过调用DrawDibProfileDisplay函数来强制重新进行这些测试。 J- l# B' C I3 s2 F% c
通常,取得和保存显示配置是一次性的事件。如果配置信息发现在这个系统中安装了另一个显示驱动时,DrawDib则重新进行测试。
- A$ f2 l: f1 }0 P: x
1 v& l. I6 V; K3 G1 ?图象再现 : i. E, m* S0 r( _. {4 R
创建了DrawDib DC后,就可以用DrawDibDraw函数将DIB绘至屏幕。当在8位深度的显示适配器上显示真彩色图象时,DrawDib将自动地抖动图象。 2 f, G* f- G9 i B
DrawDib也透明地支持视频压缩器。当显示压缩位图时,可通过DrawDibGetBuffer函数得到包含了解压图象数据的缓冲区。如果位图是未压缩的,则DrawDibGetBuffer返回NULL。在应用程序中应自己区分位图是否压缩。 - y" k) U5 k; ?
可用DrawDibUpdate宏来刷新一幅图象的整体或一部分的显示。 9 {4 S1 v+ u" y0 V
# K) U# S1 N" s" o# p" J图象序列 1 b/ o3 \, [2 h p
当DrawDibDraw函数同DrawDibBegin函数一起运用时,可以显示相同尺寸和格式的位图序列。DrawDib通过DrawDibBegin准备绘图的DrawDib DC来提高DrawDibDraw的效率。如果,应用程序没有调用DrawDibBegin,那么DrawDibDraw会在绘图前隐含地执行DrawDibBegin。
! T* N0 @" j w B0 M DrawDibBegin给DrawDibDraw提供了DrawDib的DC,DC的句柄,BITMAPINFOHEADER结构的地址和源矩形及目的矩形的尺寸。当要显示一个位图序列时,DrawDibDraw要检查序列中的每幅图象的这些值。如果DrawDibDraw检测到这些值有任何变化,它将隐含地再次调用DrawDibBegin来调整DrawDib DC的设置。 ' [5 {# q; U2 N: J( m& A
当调用完DrawDibBegin后,就可以指定一个或多个适当的标志来调用DrawDibDraw绘制图象序列。只要DC句柄未改变,就可指定DDF_SAME_HDC标志;下列参数未改变,就可指定DDF_SAME_DRAW标志:BITMAPINFOHEADER结构的地址和源矩形及目的矩形的尺寸。
7 A. s4 q# R4 p) c" m# f 可以通过在DrawDibEnd后跟另一个DrawDibBegin调用来更新前一个DrawDibBegin设置的标志。DrawDibEnd清除了当前的DrawDib DC的标志和设置。后续的调用DrawDibBegin将重新初始化DrawDib DC,并重新设置适当的标志和设置。然而,只要至少改变了以下任一个当前的标志设置:BITMAPINFOHEADER结构的地址或是源矩形或目的矩形的尺寸,也可不使用DrawDibEnd而直接调用DrawDibBegin来更新一个DrawDib DC。
1 p4 r& k* L( U8 x2 M$ T 通过使用DrawDibStart和DrawDibStop函数,可以提高使用压缩图象的数据流操作(如回放一个视频片)的DrawDibDraw的效率。DrawDibStart通过发送一个消息告诉视频管理器(VCM)准备DrawDib DC来接受一个图象流。当流结束时,DrawDibStop发送一个消息给VCM来指示它释放申请的资源。 + C: s+ J, L) g2 ~. I
需要注意的是,在应用程序中必须确定源矩形和目的矩形的宽度和高度;然而却并不需要确定这些矩形的起点。应用程序可以重新DrawDibDraw中的起点坐标来使用图象的不同部分或更新显示的不同部分。
5 y- H G8 a1 b6 W
E9 ]; h1 R1 ^& Y" z
; X: j8 v8 T2 U1 Q, z# d' M调色板
( F8 z# r# @" b) B$ A DrawDib函数组需要响应两条调色板消息:WM_QUERYNEWPALETTE和WM_PALETTECHANGED。如果应用程序未注意到调色板,就需要对这些消息都增加一个各自的消息处理。
R( U/ L; ]/ J! b 通过使用DrawDibRealize函数可在当前DC中实现当前DrawDib的调色板。应当在响应WM_QUERYNEWPALETTE和WM_PALETTECHANGED消息时,或在用DrawDibDraw函数显示一个图象序列的准备过程中实现调色板。
$ S) x* m$ i8 {% E. I$ T 可以用DrawDibSetPallette函数用另一个调色板的映射来绘一幅图象。DrawDibSetPallette强迫DrawDib DC使用指定的调色板,而这会影响到图象的质量。例如,一个注意调色板的应用程序,可能已经实现了一个调色板并需要阻止DrawDib实现它自己的调色板。应用程序可以通过DrawDibSetPalette来通知DrawDib调色板的使用。
6 d' Q. k* c. g 通过使用DrawDibGetPallette函数可以获得当前前景调色板的一个句柄。如果应用程序使用了当前前景调色板,它并没有对调色板的完全使用权,另一个应用程序能够使这个调色板句柄无效。当使用完毕后,应用程序不应该释放调色板,那样会使另一个应用程序不能使用调色板。
* V4 @& [$ i& l$ \ A) ^0 Q- r 通过使用DrawDibChangPallete函数可以为它的调色板DrawDib来接收新的颜色值。在紧跟DrawDibChangPallete的后面的代码里,可以为调色板颜色表指定新的值。当调用DrawDibChangPalette时,在DrawDib DC中未设置DDF_ANIMATE标志的话,可以通过使用DrawDibRealize来实现调色板和DrawDibDraw重绘图象来实现调色板的改变。如果DDF_ANIMATE标志在DrawDib DC中设置了,就可以通过DrawDibDraw或DrawDibRealize来实现调色板和显示着的位图颜色的动画。通过DrawDibEnd和DrawDibBegin可以DDF_ANIMATE标志。
7 m" A5 d: h' d' y% I 如果释放了被选入DC的DrawDib调色板,DC使用调色板时会报告一个GDI错误。相反,应该使用DrawDibSetPalette改变DrawDib DC来使用省缺调色板后另一调色板。 i- {- x b4 O6 ~6 ]8 d
由于以下函数会释放DrawDib调色板,所以,除非调色板不被DC选中不应使用:DrawDibEnd,DrawDibClose和DrawDibBegin。同样的,当使用了相同的DrawDib DC,但指定了不同的绘制参数(lpbi,dxDst,dyDst,dxSrc或dySrc)或不同格式时,DrawDibDraw也会释放调色板。
# v/ b3 r; e, C Y: d: ]. I / Q/ [1 v( K8 A( S* \
时间计算
" a" I( [7 k3 d% n+ a 作为调试应用程序的一部分,调用DrawDibTime函数可以得到一些关于完全重复特定次数DrawDib操作所需时间。DrawDibTime返回以下操作的时间: 4 e9 [9 |* u$ \& K- p, u9 C
绘制一幅位图 ( s0 A( M) M) N
解压一幅位图
$ O2 A+ j; v( m; }抖动一幅位图 ; G: G- M9 y3 p" D% X( ?1 M
拉伸一幅位图
5 z% ?% X; v0 c+ s' R- \使用BitBlt函数变换一幅位图 & I9 Y# d; _* T+ p7 h4 w
使用StrecthDIBits函数变换一幅位图
" h% E3 a s. t 得到返回值后,DrawDibTime重新设置每项操作的计数和值。 % {8 i! A. V, }* z+ e
注意,DrawDibTime只在DrawDib函数的调试版中可用。
8 ]1 Z$ F! E$ U
7 Z2 _) _1 Z: d$ \. ?3 PDrawDib的使用 8 _ ~6 t' v4 @: m$ a5 v
增加调色板消息处理 5 D9 t q+ p0 @6 ^$ z p- V
下面的例子说明了WM_PALETTECHANGED和WM_QUERYNEWPALETTE消息的处理。这个例子用了DrawDibRealize函数来进行WM_QUERYNEWPALETTE消息的处理。 . V6 I. r1 W" k, w% f
应用程序应通过使目标窗口无效来让DrawDibDraw函数重绘图象来响应WM_QUERYNEWPALETTE消息。应用DrawDibRealize函数实现调色板来响应WM_PALETTECHANGED消息。
& A1 K* @! o2 ?7 J# m T3 w: b# t case WM_PALETTECHANGED:
! U0 u8 W5 K Y3 A/ F7 y0 G if ((HWND) wParam == hwnd); Z$ A4 M! [- K, u' p) g+ P9 C
break;
5 r$ ]0 H. `0 c' [" r case WM_QUERYNEWPALETTE:" V7 y0 m/ q: A7 ^5 x) ]1 `: G
hdc = GetDC(hwnd);
9 a+ {6 R4 G | f = DrawDibRealize (hdd,hdc,FALSE) > 0;+ v/ [) f2 T& s/ l. W* |
ReleaseDC (hwnd,hdc);
' {6 M( p3 h; F9 \5 q3 I ?% k if (f), F( \1 X* c6 y' ?
InvalidateRect ( hwnd,NULL,TRUE);
1 h+ v1 s( L* e4 `9 {8 K. I: d# O break;
, d/ w* } O' d6 j) @3 i( e 显示设备绘制 ' @" h1 S3 ?4 M% ~5 W7 H0 W* ~- W
下面例子用DrawDibrealize函数在显示一个位图序列之前准备DrawDib DC. 6 t6 R1 R" c% E& B* o# ^. G
hdc = GetDC(hwnd);
) K D. ^" o& Q! Z% g$ {9 H DrawDibBegin(hdd,hdc,dxDest,dyDest,lpbi,dxSrc,dySrc,NULL);; k$ b4 u" E- b/ l3 O1 \- m
DrawDibRealize(hdd,hdc,fBackground);( [+ M8 L) u" i6 D$ i! l! L: G9 z3 L
DrawDibDraw(hdd,hdc,xDst,yDst,dxDst,dyDst,lpbi,lpBits,
8 R/ G% F' X' z xSrc,ySrc,dxSrc,dySrc,DDF_SAME_DRAW|DDF_SAME_HDC);7 W9 @% a' e! G6 r
DrawDibDraw(hdd,hdc,xDst,yDst,dxDst,dyDst,lpbi,lpBits,5 q' x. T, x8 \& W% ]
xSrc,ySrc,dxSrc,dySrc,DDF_SAME_DRAW|DDF_SAME_HDC); c# B; y4 W3 Z
DrawDibDraw(hdd,hdc,xDst,yDst,dxDst,dyDst,lpbi,lpBits,2 s8 R: I; W2 I8 I2 l; L
xSrc,ySrc,dxSrc,dySrc,DDF_SAME_DRAW|DDF_SAME_HDC);
6 r( q! j4 B( i& e ReleaseDC(hwnd,hdc);
# J# x, n; a! X% u 调色板动画
1 q( @ x% G( V6 l5 n 下面用了DrawDibRealize,DrawDibChangPalette和DrawDibDraw函数演示调色板动画。
5 ?: J! n5 V# p3 @- V( s+ h. v7 \0 G 能够用DrawDibBegin函数协同DrawDibChangepalette函数改变一幅位图的颜色。首先,在调用DrawDibBegin时指定DDF_ANIMATE标志允许调色板改变;然后,用DrawDibChangePalette函数从调色板入口设置颜色表的值。
! {: V3 B) `/ V" N) }8 \2 Z3 V 例如,如果lppe是一个包含新颜色的PALETTEENTRY队列的地址,并且lpbi是在DrawDibBegin或DrawDibDraw中使用的LPBITMAPINFOHEADER结构,则后面的程序片段更新DIB的颜色表。 ! j& {5 @- l' M/ P! _
hdc = GetDC(hwnd);
0 @& c# u2 p" W- {+ C/ W DrawDibBegin(hdd,…,DDF_ANIMATE);
- d9 \1 v5 O6 {( V2 d$ S+ n DrawDibRealize(hdd,hdc,fBackground);
0 o I. E5 Z8 ]3 ^7 ? DrawDibDraw(hdd,hdc,…,DDF_SAME_DRAW|DDF_SAME_HDC);9 I" ], l8 W; Q* r+ p
//改变颜色调用
0 E Z6 a/ Q1 S. `- [ DrawDibChangePalette(hdd,iStart,iLen,lppe);
+ ~( `; t1 ^8 J0 t8 f F# z' a* } ……
. h" Y' g6 r# x L$ \ ReleaseDC(hwnd,hdc);
! B/ R! v* d/ W& r( `9 m 下面给出一个实例的关键片段加以说明:(在Visual C++ 4.2 下Windows95或Windows NT环境下通过。)
3 v- Y0 K% }" x) U void CTestDrawDibView::OnDraw(CDC* pDC)
" V) Q, X( o$ q& b {
% z: R7 e8 Z( f0 ]4 A CTestDrawDibDoc* pDoc = GetDocument();//得到文档指针
6 V, h( ~. H% A! s ASSERT_VALID(pDoc); 1 {: K! w" X b8 [
// TOD add draw code for native data here
8 s, l* N% U/ _* f m_DibMem = pDoc->m_Buf;//得到DIB的内存 , o- W- G8 Z7 ^, ^
if (m_DibMem == NULL)
5 q0 `# S' ^- Z) ]4 u7 \: K$ \ S { + T! [! E4 c \ H
//AfxMessageBox("Error in m_DibMem");
: P- u. f: c8 m3 g. Z5 m8 g% v" U return;
7 J+ U9 R7 Y* y/ m: B* D* y }
2 O' v: k9 B# F3 l, Y" m+ j UINT offset = pDoc->m_Off; //得到DIB数据的偏移
& r8 d# f" Z% i; `. s- s int xDst,yDst,dxDst,dyDst,xSrc,ySrc,dxSrc,dySrc; ' Z0 o" u9 s) C( T' A
LPBITMAPINFOHEADER lpbi;
2 n4 W" |3 h4 E0 Z LPVOID lpDibMem;
6 N5 X& u! J" D8 e LPVOID lpbits=NULL; 8 F, E3 L' p2 b- x. Q
// get the Windows width & height 得到窗口的宽高
; t4 i; C& O$ \+ ` RECT rect; , w/ L6 }( q1 T2 Y. Q
GetClientRect(&rect);
' j( W! u0 W( ` xDst = yDst = 0; 3 a, \. o9 N1 \- o0 K4 h& i" Y
dxDst = rect.right - rect.left; - _. W) Q, x2 T& j- ^0 M& u
dyDst = rect.bottom - rect.top; + D K! w: m/ j- Y8 R- H* g8 I
// Get Dib info得到DIB的信息 ) x- {, u! A, A: v7 c
xSrc = ySrc =0; # b5 g" b) k# q( J
lpDibMem = GlobalLock(m_DibMem);//锁定内存得到指针
7 P" [( }- ?2 J lpbi = (LPBITMAPINFOHEADER)lpDibMem;//得到DIB信息 ; ^& z- E- _( n1 J7 Y0 A1 B1 q
dxSrc = lpbi->biWidth; ' |' }5 M2 c9 z. Q# J$ R
dySrc = lpbi->biHeight;
* f% u3 w1 y& _& p1 C- J lpbits = (LPSTR)lpDibMem + offset - sizeof(BITMAPFILEHEADER); & s }+ d+ c# d
// Draw Dib绘DIB
) }( i# X' L3 W; ~- r6 d/ L HDC hdc = NULL; . [; }% \: o% I' b7 `& l5 p% a
hdc = pDC->m_hDC;
4 g$ J. g2 h$ k+ H8 W" X /*
% T2 I! w# \2 ^! r/ U1 g // Using SetDIBToDevice使用SetDIBToDevice函数为对照
" M0 A: e" ^/ I' [ int line = SetDIBitsToDevice(hdc,4 ^& f/ \2 c! B, U0 r9 y1 p
xDst,
! R% l, B& [6 Y; [ yDst,
9 B7 z' b) f' q3 | dxSrc,( B# ?0 T; I" d- ?" q. |
dySrc,
' a3 i p) z5 y# p' y f* | xSrc,. y$ p4 i I* O* u
ySrc,
; g1 ^; n* p. Q% I6 ^: G 0,
6 y& I2 V# \. C/ b( V dySrc,
, H$ A( a3 d7 t* D lpdib,//lpbits,! C0 o8 r% V ^5 f# F! v+ _
(LPBITMAPINFO)lpbi,, e2 m7 S* z3 ?4 h8 N
DIB_RGB_COLORS); ( ?# U; C' V% Q. C
if(0 == line)
# y3 I! U( t& Q { 1 _$ Y1 s4 B4 R9 R9 D5 I3 `
AfxMessageBox("Error in SetDIBsToDevice");
. Q" t$ P4 U7 H } % ?# o) v; z; X' V
*/
; S6 n; t- `: L, e. K6 V/ H /*
5 |0 [/ ?$ }# x) G // Using StretchDIBits使用StretchDIBits函数为对照 ) J; e* N+ i a. a6 C- v9 J; I
int line = StretchDIBits(hdc,$ K0 S* u3 F+ r6 b0 G! y
xDst,$ W& `1 O8 N0 y' e( k l
yDst,
2 I9 c: v8 |9 `; F: [( K- B! J8 z dxDst,
' R- q- O5 Y- s* | dyDst,0 m- v, ]2 H/ S( Y$ O
xSrc,
5 P, b P/ |" x5 c9 F# c ySrc,1 V$ D* N7 }9 X! A3 ^* |
dxSrc,
; @7 S& W' ] p4 M dySrc, . p, y. q; ?9 m4 L5 }: x
lpbits,
+ S4 a: ?1 D8 Y V( g0 R- n (LPBITMAPINFO)lpbi,4 Z% ]0 f, g: O5 l% X" S* r" A
DIB_RGB_COLORS,- U) _0 g& \$ {
SRCCOPY); # c. m: `4 Z, H2 \
if(0 == line) . m, [' j' Y6 S, U6 b: L4 _; _* G
{ ! w6 _# B1 b2 y ^) v
AfxMessageBox("Error in SetDIBsToDevice"); % e2 f& S- b! b
} ! h, u @! B5 w+ L% q U
*/
8 x* H0 t: F: |5 _* ^0 d5 l // Using DrawDib使用DrawDib
^% ~ C3 h& S* n // Set Dawing flag设置绘制标志
5 {* A4 q- T4 | h8 g" e, B8 h8 h8 z UINT wFlags; 8 t- a; T I+ _9 ?
//标志意义参见前面的函数参考,以下两个标志可绘出图象, : W/ x5 `' {5 e
//其余标志在这种情况下绘不出图象。 . ]" @ S3 E5 r3 g# c
wFlags = DDF_DONTDRAW; ! d! U# m0 w8 M9 ~/ J0 a
//wFlags = DDF_NOTKEYFRAME; - k( o1 T; _4 Z
HDRAWDIB hdd = DrawDibOpen();
$ G1 K% b# x# S; X2 y if (hdd != NULL)
8 G0 s) v% U: `$ Z2 _9 i E {
* Q, ]/ J7 y: Z) ^0 k BOOL Suc = TRUE; 0 A& g* ~5 H, [8 b
//具体参数请参见前面函数参考 , @6 K7 g2 M+ j8 H
Suc = DrawDibDraw(hdd,+ Z7 y8 r& d+ _" b
hdc,5 g) b( l; q9 L0 @
xDst,9 K `1 v1 e$ y2 K: z5 V3 |
yDst,
. e* H: _. \6 }& F% ~ dxDst,
# u" w5 X& A* I% d# G! p dyDst,
; u" E0 A) @( ~' b5 a# K" A7 T lpbi,
2 R5 R6 _9 V. l5 e6 r! E lpbits,1 ?! _% Y& {& b9 w0 D8 D
xSrc,' u9 Y" u6 \* Z1 d* m) _
ySrc,
6 A. B9 s% w0 t- `4 F2 I4 e dxSrc,
# [, N; V: ]4 G1 n dySrc,0 o" _/ A+ [4 [- _4 a k# d
wFlags); 7 }) B/ O1 X7 K5 k5 N! K
if(Suc == FALSE) AfxMessageBox("DrawDib Failed");
5 k5 g4 @7 _- }, J1 F: M2 N' Z& t /* //时间测试 % m2 T6 z% z# W! w$ ?( T2 A
DRAWDIBTIME time; ' e/ O5 }( i5 P% i1 f, o, \0 {
DrawDibTime(hdd ,&time);
- C4 {* S1 ]3 y! t1 H$ @" b+ g char buf[256]; + R& A/ L$ t. Y$ e: y1 |
sprintf(buf,"Count %d\nDraw %d\nDecompress %d\n
5 \# c( g, n" H Dither %d\nStretch %d\nBlt %d\n SetDIBits %d\n",
+ f/ c" n& j- U* M4 R% V time.timeCount,time.timeDraw,- H* Y" K- _& X) @# _; {5 ]- W
time.timeDecompress,time.timeDither," V: ?" @% J; @' @0 J$ v4 B
time.timeStretch,time.timeBlt," ~5 ` i! T' S$ b1 }: x+ \5 O# m
time.timeSetDIBits); 8 H/ i$ m! Z1 K1 w! r
AfxMessageBox(buf); + L4 z9 U. T, ~# n: t
*/
0 b6 g8 s6 \- d. A9 R DrawDibClose(hdd); ; M# B" ~2 u. J+ j
} O7 c* l# F: S* Z3 S- t( y4 b
else
- N+ A5 k5 ]( t AfxMessageBox("Error in DrawDibOpen");
! y$ V! B6 i6 a$ R5 F GlobalUnlock(m_DibMem);//释放DIB句柄
% ^/ l4 h- y' J/ I6 x } * C) k1 |6 m0 Q; |
5 `4 Q1 ?4 z3 ?- x/ U* l& `0 h/ p附:函数参考: X+ }- [1 B$ F1 l) Y% a, T
DrawDibBegin
8 w$ p+ W; t+ G4 c这个DrawDib函数改变一个DrawDib DC的参数或初始化一个新的DrawDib DC.
7 F0 D* [0 Y+ F9 j+ g. x- JBOOL DrawDibBegin( 9 t* u% z: I5 |) P2 _ R
HDRAWDIB hdd,
# E4 }7 @+ p3 c/ QHDC hdc, ; {) ]0 v( P; f- U/ i9 L3 I2 R
int dxDest,
8 x6 b0 G3 d9 C/ kint dyDest, 5 Z% M/ R. z- M
LPBITMAPINFOHEADER lpbi,
( |$ j2 `4 _2 L c/ Z* ^0 [int dxSrc,
9 C! D/ E9 n9 ?6 _int dySrc,
+ m6 H; F: u+ j9 C+ f9 C6 }UINT wFlags
! F" S0 ]1 T5 s5 p& t); " W- c. @/ L9 S. x- p6 `
参数
5 T; H+ y, W( u) y0 x7 Qhdd DrawDib DC的句柄
$ |' U; x9 N/ ~- F2 O* }' Z! Ihdc 绘图DC的句柄。此参数为可选。 # g, r D; T7 g& f# W% |9 J4 N
dxDst和dyDst 在MM_TEXT方式下目的矩形的宽度和高度。
F+ J0 z) b: U% V# L2 }6 s1 S, blpbi 包含图象格式的BITMAPINFOHEADER结构的地址。DIB颜色表紧跟图象格式,并且biHeight成员必须为一正值。
& ~: m5 v5 d+ F/ B0 X% m4 tdxSrc和dySrc 源矩形的宽度和高度(以象素为单位)。 ) z2 C; |" ?) I) ]
wFlags 函数调用的可用标志。定义了以下的值:
& Q' I+ j! ]) ?+ eDDF_ANIMATE 允许调色板动画。如果这个值被设置,通过在LOGPALETTE结构中设置palPalEntry成员PC_RESERVED标志,则DrawDib保存了尽可能多的入口,调用drawDibChangePalette函数就可实现调色板动画。如果应用程序用了DrawDibBegin函数协同DrawDibDraw函数,最好在DrawDibBegin中设置这个值而不在DrawDibDraw中。
/ _, S1 a$ T r4 @DDF_BACKGROUNDPAL 实现作为背景的调色板,保留当前显示所使用的调色板不变。(这个值与DDF_SAME_HDC互斥。) 4 g9 U8 n. Z; u( _
DDF_BUFFER 使DrawDib使用屏幕缓冲,这样DDF_UPDATE才可使用。这关闭了解压和直接绘屏。如果DrawDib不能创建一个脱屏缓冲,就解压或直接绘屏。 ) p" p X+ x) U3 J
DDF_DONTDRAW 当前图象未绘,但已解压。DDF_UPDATE能够以后被用来绘图象。这个标志取代了DDF_PREROLL标志。 G I j+ k# t5 h4 {
DDF_FULLSCREEN 不被支持。 0 k8 e& f" j& N" T
DDF_HALFTONE 不管DIB的调色板如何而把DIB抖动成标准调色板。如果应用程序用DrawDibBegin协同DrawDibDraw,在DrawDibBegin中设置这个值而不在DrawDibDraw中。 ( J8 q5 {. P1 H+ V W0 p, `4 A8 N
DDF_JUSTDRAWIT 用GDI绘这图象。禁止DrawDib函数解压,拉伸或抖动图象。这实际上剥夺了DrawDib区别于StrechDIBits函数的能力。
; p& {5 S7 k @9 p8 o* F3 N1 `9 zDDF_SAME_DRAW 让DrawDibDraw使用当前的绘制参数。只有当从使用DrawDibDraw或DrawDibBegin起,lpbi、dxDext、dyDest、dxSrc和dySrc就未改变才用这个值。这个标志取代了DDF_SAME_DIB和DDF_SAME_SIZE标志。 1 P/ `6 V) o; d4 y- k: |$ H" J
DDF_SAME_HDC 使用当前DC句柄以及与当前句柄相关联的调色板。 % t2 Z( A& Z' z7 e# I w/ y
DDF_UPDATE 最后缓存的图象需要绘制。如果用这个值绘制失败,则缓冲的图象不在有效,并且在显示被更新前,需要指定一幅新的图象。
5 w! S$ ` Y. P返回值 ) P+ D0 d; n. g# E9 F9 e: Z
成功返回TRUE,否则FALSE。
0 t' ~2 G+ f' z" ^. Q4 Z) P# ?注 这个函数准备由lpbi指定要绘往DC的DIB。图象已经拉伸成由dxDest和dyDest所指定的大小。如果dxDest和dyDest被设置成-1,DIB则被按原比例绘制。 1 j: l' p" j2 }: b8 A
可通过重新使用DrawDibBegin,指定新的标志和改变至少一个以下的设置:dxDest、dyDest、lpbi、dxSrc或dySrc来更新DrawDib DC的标志。
2 l. x% {6 U3 C& h0 l% s' x; O如果DrawDibBegin的参数未被改变,再次调用这个函数将不起作用。 : h* c; L( h1 L5 _7 p$ S/ O
DrawDibChangePalette
, C7 w' ]6 D$ D/ L) E$ s9 c6 l这个函数设置绘DIB所用的调色板。
: w2 x$ @4 f' W) UBOOL DrawDibChangePalette(
J% I3 w" W4 }" iHDRAWDIB hdd,
# i( g" Y! ^' `: x) y% yint iStart, / x2 A" I- D" }$ D. A3 x: I
int iLen,
+ H7 V0 n5 n S5 e$ vLPPALETTEENTRY lppe ( E0 z0 f0 G5 O
); 5 `- g% U! k# T' @0 z
参数: ; m S7 F0 ]4 Z8 s" |/ n
hdd DrawDib DC的句柄。
" y) w+ O1 G2 n n8 l! p+ ]iStart 调色板开始数。
3 p8 h2 S% k3 y7 W+ miLen 调色板的数目。 $ h1 W* Z8 Q1 R/ B, }! N
lppe 调色板阵列的地址。 . T1 `9 Z/ i @" a
返回值
; l0 A" i# b1 y" F+ z$ ?成功返回TRUE,否则FALSE。 4 V2 u k, b1 B& }/ ~7 S
注 只有当当前DrawDib调色板是调用DrawDibRealize函数实现时,这个函数改变物理调色板。 4 y4 ^# i. j$ a8 C2 x$ N& z
如果颜色表没有改变,下次没有指定DDF_SAME_DRAW的DrawDibDraw函数将隐含地调用DrawDibBegin函数。 9 A) Y, A5 W/ i) g
DrawDibClose 3 H; o% ?4 R( a) C$ A: U" ~
这个函数关闭一个DrawDib DC并释放DrawDib申请的资源。 # a9 J- S* k3 x1 k
BOOL DrawDibClose( 9 Q1 J" Q* ]/ Y
HDRAWDIB hdd
) v" t* Q5 E- \);
/ v3 v( I! _( U, o; v参数 ) M8 B/ b% _- Q4 T6 t& k8 {7 r& y
hdd DrawDib DC的句柄。 # N3 m0 x( R7 m2 m5 }
返回值 ( x6 b; {% ~6 U7 v" }2 f
成功返回TRUE,否则FALSE。 # l+ ^. E% ? r, l, X' S* n
DrawDibDraw
' R. c7 |/ z" S& _# Q# y, C这个函数将DIB绘至屏幕。
3 x2 V$ A4 \5 t: [. P! FBOOL DrawDibDraw( " o6 O" H7 V! n+ i( h% K) U
HDRAWDIB hdd, & @* s; w# }3 q o9 q, { ~
HDC hdc,
. ~1 z+ }: @' z4 s( {' Lint xDst,
- {2 b6 g3 s8 D5 j: n/ `int yDst,
l8 ]. n! l: m: u& Dint dxDst, & ~4 \. E H+ {
int dyDst, 0 s' n; }' j( h
LPBITMAPINFOHEADER lpbi, 2 Q+ @! G' R) _2 |- f
LPVOID lpBits,
# ?- Y- P& |4 z ~# Aint xSrc,
, ?8 \ {- T8 ^9 fint ySrc,
7 G3 U# ?+ ?1 B, l1 sint dxSrc, . l' `" B$ g" q, f) Z; |/ |/ P
int dySrc, * M: F7 r8 w0 R5 z
UINT wFlags
. \4 ^' T1 M# S, V+ H);
6 H4 D J$ l6 u" v4 I参数 * c. k9 t: o M7 F. U C. t
hdd DrawDib DC的句柄。 / A! u- M, `7 D, M8 ]7 E2 }
hdc DC的句柄。 + N, k, i2 E; S
xDst和yDst 在MM_TEXT坐标系,目标矩形左上角的x和y坐标。
% g) L7 _. D. V6 c+ \dxDst和dyDst 在MM_TEXT坐标系下,目标矩形的宽度和高度。如果dxDst为-1,则使用位图的宽度;如果dyDst为-1,则使用位图的高度。 : @- N9 } S# y, _& l a
lpbi 包含图象格式的BITMAPINFOHEADER结构的地址。DIB的颜色表紧跟着格式后,并且biHeight成员必须为正值;DrawDibDraw不能绘制倒置的DIB。
( c9 x: D9 A: `% rlpbits 包含位图位的缓冲的地址。 1 w# _5 u6 }. P6 c3 A+ G
xSrc和ySrc 以象素为单位,源矩形左上角的x和y坐标。坐标(0,0)是位图的左上角。 " Q g9 V( m8 r9 G/ D% q2 c2 X
dxSrc和dySrc 以象素为单位,源矩形的宽度和高度。 : Y1 ^# ]2 Z7 ^6 {3 |! u0 E& Z
wFlags 可用的绘图标志。如下值被定义:
* g1 e1 H3 I" u7 I$ K' SDDF_BACKGROUNDPAL 实现作为背景的调色板,保留当前显示所使用的调色板不变。这个值只有当DDF_SAME_HDC未被设置时才有效。 + d7 p3 a7 D* Y
DDF_DONTDRAW 当前图象已解压但未绘。这个标志取代了DDF_PREROLL标志。
& |1 Q* n4 H) a4 W; l& C0 ]DDF_FULLSCREEN 不被支持。
' c. b2 N1 _, P0 D( fDDF_HALFTONE 不管DIB的调色板如何而把DIB抖动成标准调色板。如果应用程序使用了DrawDibBegin,在DrawDibBegin中设置而不在DrawDibDraw中。 ) ~1 x# ]% f* L! G2 B
DDF_HURRYUP 数据并不需要被绘(它可以被绘)并且DDF_UPDATE不用理会这个信息。DrawDib只有当需要去构建另一帧时才检查这个值;否则,这个值被忽略。 ; P$ H7 c9 o( V3 t1 C7 ^/ ~; c
这个值通常用来同步视频和音频。当同步数据时,应用程序应当用这个值发送图象以防止驱动器需要缓冲帧来解压后续帧。 2 R, ?$ \/ s6 p) B+ M' b7 g
DDF_NOTKEYFRAME DIB数据不是关键帧。
) I2 _0 {/ }+ jDDF_SAME_HDC 使用当前DC句柄以及与当前句柄相关联的调色板。 - k2 L, J* E2 A2 g. q4 l
DDF_SAME_DRAW 让DrawDibDraw使用当前的绘制参数。只有当从使用DrawDibDraw或DrawDibBegin起,lpbi、dxDext、dyDest、dxSrc和dySrc就未改变才用这个值。DrawDibDraw经常检查这些参数,如果它们改变了,DrawDibBegin则准备绘图的DrawDib DC。这个标志取代了DDF_SAME_DIB和DDF_SAME_SIZE标志。 0 ^' p8 h( ]- Y, M$ a$ c
DDF_UPDATE 最后缓存的图象需要绘制。如果用这个值绘制失败,则缓冲的图象不在有效,并且在显示被更新前,需要指定一幅新的图象。 1 p% |# i- o7 K& M" I
返回值 ) r8 ^% d* x- @. i% e Z! m' l2 K
成功返回TRUE,否则FALSE。 $ m2 W- F# j0 U
注 DDF_DONTDRAW使DrawDibDraw解压但不显示一幅图象。一个调用DrawDibDraw的序列是指定DDF_UPDATE来显示图象。
, H0 q. l- J5 u' e- F如果DrawDib DC没有指定一个屏幕缓冲,指定DDF_DONTDRAW会造成这帧被立即绘到屏幕。序列调用DrawDibDraw指定DDF_UPDATE会失败。
' J- V# ?2 K Z! {1 z尽管DDF_UPDAT和DDF_DONTDRAW可以在不同时间设置,它们可以一起用来创建脱屏图象。当脱屏图象完成后,可以调用DrawDibDraw来显示图象。
6 N7 ~$ e6 G' |0 Z: [0 {DrawDibEnd
/ V, E/ [4 j# C, A0 U+ }0 E, I" m这个函数清除由DrawDibBegin或DrawDibDraw函数设置的标志和DrawDib DC的其它设置。 3 O# H+ T9 v ~
BOOL DrawDibEnd(
: j" K, a9 G8 x2 }( c# NHDRAWDIB hdd
' l9 P! l* L% E. T, g9 D E% \! S);
- t: ^: _; s1 `" I- z8 f: Z) Q参数 0 Z1 }8 ^! [5 g# U
hdd 要释放的DrawDib DC的句柄。
* h( ?5 K/ N& j返回值
) O( [3 S* p" k% a% M! j: w9 Q a成功返回TRUE,否则FALSE。
3 `/ B1 c U [0 m xDrawDibGetBuffer 1 ]& r2 V1 H" V5 L# ?0 Y
这个函数清除由DrawDib用来解压的缓冲的地址。 6 o1 K! D7 d/ u2 `6 X
LPVOID DrawDibGetBuffer(
- G" @7 {: R Q" i4 ?HDRAWDIB hdd,
5 D" H$ ?, Q) n0 f3 C( O9 R3 a, B9 ZLPBITMAPINFOHEADER lpbi,
) |9 f a3 r4 w/ S( p: t# P) WDWORD dwSize, . C A' f& D/ T' x" D! x/ @
DWORD dwFlags
' i. u7 o, F8 D' Q- W9 C, n); ! m5 v8 h' q E+ i# Q" N! z4 E
参数 " ~0 Q+ a6 G0 R! a9 k' ], J
hdd 要释放的DrawDib DC的句柄。 ' H# K7 p: p/ s+ ?% c! Q
lpbi BITMAPINFO结构的地址。这个结构由BITMAPINFOHEADER结构和位图使用的256色调色板所定义的颜色表。
( x; E- s$ K! e( tdwSize 通过lpbi的BITMAPINFO结构所指的字节大小。
. G* R$ n) [& m& z. T9 T. A# ]dwFlags 保留,必须为0。 3 K; b, b% e6 G* q& v
返回值
6 p( o/ D! ]5 [8 {9 p返回缓冲的地址或者如果没有用到缓冲返回NULL。如果lpbi不为NULL,它填充了一个描绘缓冲的BITMAPINFO的结构。
4 \0 e- w- a, ?$ R) q* C* IDrawDibGetPalette 0 U |, \- v5 d Y
这个函数清除由DrawDib DC所使用的调色板。 2 s$ w& T3 @% ? P% P# {8 S$ M* }
HPALETTE DrawDibGetPalette( : B$ I- Q8 H" b/ I' z
HDRAWDIB hdd , J0 Z, K9 Z- `7 o6 b' K0 N
);
* V4 J3 c* A% V; D ?参数 ) {/ \& P3 d, A) {. [
hdd 要释放的DrawDib DC的句柄。 # |5 x+ R+ z( \( B1 J- r
返回值 8 a; _, e- l M) q/ _- m m7 ]
成功返回一个调色板句柄,否则返回NULL。 " B8 d% t. a0 t( o2 q0 Y/ I
注 这个函数假设DrawDib DC包含了一个有效的调色板,隐含着这样的一个条件:对这个函数的调用必须在DrawDibDraw或DrawDibBegin函数之后。 $ u7 c1 a: |& t( c
DrawDibOpen
- J+ u ~1 i0 U. ~- z2 @/ {' @这个函数打开DrawDib库为使用和创建一个绘图的DrawDib DC作准备。 ' Z: I, j* _$ S# Q9 L2 B6 X5 D* N: v9 C
HDRAWDIB DrawDibOpen(VOID);
) ]3 h4 N9 E: K: v# N' X$ V参数
# P- T j5 g5 i3 c9 O+ x这个函数不需要参数。
7 a. p$ y1 n, F( F7 [0 t$ ?( [返回值 & }( C+ c3 y0 F5 \! K8 ]; }- K8 ~
成功返回一个DrawDib DC的句柄,否则为NULL。
* D9 N: Y5 J* b注 当同时绘多个DIB时,为同时在屏的每个图象创建一个DrawDib DC。
3 n. ]# V' z0 |2 P" q* Q: gDrawDibProfileDisplay
% k. y: q8 L3 U# X: Z O5 z: g$ U这个函数决定了当用DrawDib函数时显示系统的设置。
7 J5 Q; i1 g9 j5 d. k3 |BOOL DrawDibProfileDisplay(
4 d; h$ W- n8 s' ^/ WLPBITMAPINFOHEADER lpbi
3 X1 P9 r, p. ^) I2 J* B);
& y/ K) j2 J# e/ i4 y/ b4 i+ `参数
1 q3 h2 M# X" Ulpbi 包含位图信息的BITMAPINFOHEADER结构。可以通过指定NULL来确认配置信息是当前的。如果配置信息不是当前的,DrawDib会重新运行配置测试来得到当前设置信息。如果把这个参数设为NULL来调用DrawDibProfileDisplay返回值是没有意义的。 , h0 N1 x1 Q1 h5 _& X* h
返回值 ) L% Q) ~5 D7 o P' y
返回值指出了这个显示系统的最快绘制和拉伸能力。如果位图格式不被支持,这个值为0或一个或更多的下列值: 9 {. D* O/ o a9 O% B& o
PD_CAN_DRAW_DIB DrawDib能用这种格式绘图象。拉伸可能被支持或不被支持。
' H- e m* @+ a/ PPD_CAN_STRETCHDIB DrawDib能用这种格式拉伸或绘制图象。
' @4 s4 V" ]' V c+ @5 CPD_STRETCHDIB _1_1_OK StretchDIBits用这种格式绘未拉伸的图象快于另一种方式。 5 x& u, q5 E) E8 Q% z, e2 K
PD_STRETCHDIB _1_2_OK StretchDIBits用这种格式绘以1:2拉伸的图象快于另一种方式。 , D: f+ w: Q. @7 r
PD_STRETCHDIB _1_N_OK StretchDIBits用这种格式绘以1:N拉伸的图象快于另一种方式。
# | B+ f, x, T4 M1 E5 ]DrawDibRealize * J# v2 Y4 V. V4 h/ k
这个函数为用指定DC实现DrawDib DC 的调色板。
6 H @4 y1 C( aUINT DrawDibRealize (
- T) ]3 P' z7 \) G& y$ ~" O( iHDRAWDIB hdd ,
8 }2 B* v, J `1 l8 @HDC hdc ,
! N- V, d# D h6 _2 u# g! \BOOL fBackground 5 }8 g" P8 G% N, f6 ]
) ;
3 y" D* Z( U! @& \参数 4 z6 v! S$ A& V
hdd DrawDib DC hdd DrawDib DC的句柄。 - T$ @8 L) `* L
hdc 包含调色板的DC的句柄。 ' z5 B6 }" @, E+ Q$ P& ]3 K
fBackground 背景调色板标志。如果此值非零,此调色板为背景调色板。如果此值为零并且DC与另一个窗口相连,当窗口拥有输入焦点时逻辑调色板变为背景调色板。(当窗口风格是CS_OWNDC或当DC是用GetDC函数得到的时,一个DC就与一个窗口相连)。
X" w6 M& `' s返回值 & M8 e, R5 c6 |* A" J& O2 J$ c- ^
返回在系统调色板中映射了不同值的逻辑调色板中的入口值。如果发生了错误或没有要更新的颜色,返回0。
" \, V% c2 z" V5 _注意
& G: B7 e8 l3 V; \2 h用DrawDibDraw函数并指定DDF_BACKGROUNDPAL标志来选择DrawDib DC的调色板作背景调色板。
; m5 G: k$ e9 s' IDrawDibSetPalette
3 w) k8 _" P* |这个函数设置绘DIB所用的调色板。 . [0 N* p) f5 C5 [2 Y4 H5 w
BOOL DrawDibSetPalette(
^* C+ a1 c- i% l9 J' |, ZHDRAWDIB hdd , - J( S3 c2 _* P4 c/ ?1 d0 F8 O
HPALETTE hpal
$ f9 c. h) A5 a, K0 e) ; 4 N V; q4 }7 ~- B* y. Y1 z
参数
; S) t: N7 f" u7 @4 U' v5 nhdd DrawDib DC的句柄。 7 U# L* Y! l" b3 M3 _7 }
hpal 调色板的句柄。指定NULL则使用缺省调色板。 ) E1 S- R% v& ~1 S& {
返回值 ' T! [9 n) ?" J* ]$ `( h
成功返回TRUE,否则返回FALSE。
. w4 ?& j3 G" X) j0 \. b1 F, r' k) Q/ YDrawDibStart $ L. {7 \9 ^! t$ Q# {5 s
DrawDibStart函数为流回放准备 DrawDib DC。 ! R$ i1 w+ Q) K$ T/ K X
BOOL DrawDibStart( - |1 G( v/ Z# g# R$ U
HDRAWDIB hdd , * x5 x& p9 u* l1 ?
LONG rate
8 i5 _5 \3 r3 ?4 R1 c); % N& l* r8 Y, l* Z- ^7 g
参数
3 f* n( R/ _! Ghdd DrawDib DC的句柄。
8 `/ s3 k2 q" Y4 n# d1 Rrate 回放率 每帧以毫秒计。
" W- U8 a6 o2 K" B3 ?: H返回值
- _3 I; T5 ~( W a' L成功返回TRUE,否则返回FALSE。
8 J, J: i3 }9 {4 [. {7 k+ qDrawDibStop 6 G0 k1 s; |' F/ C; I: F
这个函数释放用于流回放的DrawDib DC所占用的资源。
; R s5 I1 M3 o& `7 a$ f! `BOOL DrawDibStop( ( X* a; v3 u# H" E
HDRAWDIB hdd
0 P! R; L0 f! q); + k6 {& w! w( P
参数
" G6 D7 [& \0 \$ L) u& V8 Zhdd DrawDib DC的句柄。 3 O- \. ]4 H/ Y) t3 E9 h
返回值
. ^. n) g% D5 b8 K& |成功返回TRUE,否则返回FALSE。 * Y1 H7 l; L/ ]4 e2 A+ h
DrawDibTime
" u3 g* x% {# l! G2 z& g* Q这个函数得到关于绘制操作的时间和调试操作的时间信息。 4 V$ o% U3 x6 m. o
BOOL DrawDibTime(
* u1 S* A5 k7 x5 H, JHDRAWDIB hdd, . _& F R- b2 v) l! x
LPDRAWDIBTIME lpddtime
2 X. v5 j+ ^: A' v) ;
6 @- n9 m4 X1 Y W0 o; b7 }) k; G参数
; S3 I, i! {; O7 Chdd DrawDib DC的句柄。 ! P' H/ P7 I, E3 ~
lpddtime DrawDibTime的结构地址。
& \& b( t- i# C; k, ?返回值 1 l8 d& Y6 F" @
成功返回TRUE,否则返回FALSE。 - u" Q2 M, b' G5 ?
注意 4 ?1 Q0 c! V$ M# T5 \% J
这个函数只存在于W32软件开发库的调试版本。
9 S2 `: Y2 g7 a8 a" q 8 v" C8 O# t7 P4 Q7 j& m
|