观察 Windows 自带的纸牌、空当接龙等扑克游戏会发现他们都利用到了 cards.dll 这个动态链接库,从中引入了 cdtInit 和 cdtDrawExt 等函数来实现扑克的绘制等工作。其实我们也可以利用 cards.dll 来写一个我们自己的扑克游戏。下面的示意图就是一个小的测试程序,用到了 cdtDrawExt 等函数绘制了所有扑克,扑克背面的图案,反色绘制扑克等等。这里是例子代码,这里是引入 cards.dll 所需要的 cards.lib。
为了在程序中调用 cards.dll,我们首先要搞清楚的就是 cards.dll 导出的每一个函数的用法,包括参数、返回值等等。关于这一点你可以自己反汇编纸牌游戏和 cards.dll 来分析反汇编后的代码从而得出每一个函数的用法,也可以参考 MSJ Spring 1996 中的文章 Fun and Games。当然,我在后面也会介绍每一个函数的用法。
知道了函数的用法后,我们考虑要在程序中用 invoke 的方法来调用函数,就需要构建一个引入库 cards.lib。由于引入库中不需要包含具体的代码,所以我们自己写一个动态库,导出和 cards.dll 一样的导出函数,那么编译连接动态库时生成的引入库就可以拿来使用。
.386 .model flat,stdcall option casemap:none .code cdtInit proc p1:DWORD, p2:DWORD cdtInit endp cdtDraw proc p1:DWORD, p2:DWORD, p3:DWORD, p4:DWORD, p5:DWORD, p6:DWORD cdtDraw endp cdtDrawExt proc p1:DWORD, p2:DWORD, p3:DWORD, p4:DWORD, p5:DWORD, p6:DWORD, p7:DWORD, p8:DWORD cdtDrawExt endp cdtAnimate proc p1:DWORD, p2:DWORD, p3:DWORD, p4:DWORD, p5:DWORD cdtAnimate endp cdtTerm proc cdtTerm endp end
好,有了引入库后我们就可以很方便的利用 invoke 来调用函数啦。下面介绍几个主要函数的用法:
cdtInit proc lpdwCardWidth:DWORD, lpdwCardHeight:DWORD lpdwCardWidth 返回扑克的宽度 lpdwCardHeight 返回扑克的高度
cdtDraw proc hDC:DWORD, dwX:DWORD, dwY:DWORD, cd:DWORD, md:DWORD, rgbBkgnd:DWORD cdtDrawExt proc hDC:DWORD, dwX:DWORD, dwY:DWORD, dwdx:DWORD, dwdy:DWORD, cd:DWORD, md:DWORD, rgbBkgnd:DWORD hDC 设备句柄 dwX 左上角的位置的横坐标 dwY 左上角的位置的纵坐标 cd 指出绘制哪一张扑克,或哪一个背景,具体对应的序号可以参考例子代码中的 Cards.inc 文件 md 绘制方式,有以下几种 mdFace EQU 0 ;绘制各种花色扑克 mdBackground EQU 1 ;绘制各种背景 mdHilite EQU 2 ;反色绘制各种花色扑克,不支持反色背景 mdGhost EQU 3 ;绘制网格图 mdRemove EQU 4 ;采用背景颜色绘制一个扑克大小的矩形 mdInvisibleGhost EQU 5 ;绘制网格图 mdDeckX EQU 6 ;绘制 X 图 mdDeckO EQU 7 ;绘制 O 图 rgbBk 绘制背景时的背景颜色 dwdx 绘制放大的或缩小的扑克时的宽度 dwdy 绘制放大的或缩小的扑克时的高度
cdtTerm 没有参数
有关上面几个函数的具体用法我们来看看例子代码:
WndProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM local hDC:HDC local ps:PAINTSTRUCT .IF uMsg==WM_DESTROY invoke cdtTerm invoke PostQuitMessage, NULL .ELSEIF uMsg==WM_CREATE invoke cdtInit, addr nCardWidth, addr nCardHeight invoke ShowWindow, hWnd, SW_MAXIMIZE .ELSEIF uMsg==WM_PAINT invoke BeginPaint, hWnd, addr ps mov hDC, eax ;===========================\ 按每种花色的顺序绘制 4 列扑克 xor ecx, ecx xor ebx, ebx mov esi, 10 @1: mov edi, 12h mov ebx, ecx @2: push ecx invoke cdtDraw, hDC, esi, edi, ebx, mdFace, rgbBground pop ecx add edi, 12h add ebx, 4 cmp ebx, 52 jb @2 add esi, nCardWidth add esi, 10 inc ecx cmp ecx, 4 jz @3 jmp @1 @3: ;===========================/ ;===========================\ 绘制所有的可用背景 mov ebx, 54 mov esi, 10 mov edi, 400 @@: invoke cdtDraw, hDC, esi, edi, ebx, mdBackground, rgbBground inc ebx add esi, nCardWidth add esi, 10 cmp ebx, 66 jnz @B ;===========================/ ;===========================\ 反色绘制各种花色的扑克 mov ebx, 0 mov esi, 10 mov edi, 500 @@: invoke cdtDraw, hDC, esi, edi, ebx, mdHilite, rgbBground add ebx, 5 add esi, nCardWidth add esi, 10 cmp ebx, 55 jnz @B ;===========================/ ;===========================\ 其它几种绘制方式 mov ebx, 6 mov esi, 10 mov edi, 600 invoke cdtDraw, hDC, esi, edi, ebx, mdGhost, rgbBground add ebx, 5 add esi, nCardWidth add esi, 10 RGB 255, 0, 0 invoke cdtDraw, hDC, esi, edi, ebx, mdRemove, eax add ebx, 5 add esi, nCardWidth add esi, 10 invoke cdtDraw, hDC, esi, edi, ebx, mdInvisibleGhost, rgbBground add esi, nCardWidth add esi, 10 invoke cdtDraw, hDC, esi, edi, ebx, mdDeckX, rgbBground add esi, nCardWidth add esi, 10 invoke cdtDraw, hDC, esi, edi, ebx, mdDeckO, rgbBground ;===========================/ invoke EndPaint, hWnd, addr ps .ELSE invoke DefWindowProc, hWnd, uMsg, wParam, lParam ret .ENDIF xor eax,eax ret WndProc endp
怎么样,再看看前面的示意图,3.5KB 就有这样的效果,是不是很酷!在代码区还有一个用 C+SDK 方式编写的空当接龙源代码,大家如果有兴趣可以看看。
CopyRight (C) 2001-2004 一块三毛钱本文地址:http://com.8s8s.com/it/it1064.htm