以文本方式查看主题

-  计算机科学论坛  (http://bbs.xml.org.cn/index.asp)
--  『 C/C++编程思想 』  (http://bbs.xml.org.cn/list.asp?boardid=61)
----  利用 cards.dll写自己的扑克程序  (http://bbs.xml.org.cn/dispbbs.asp?boardid=61&rootid=&id=85033)


--  作者:卷积内核
--  发布时间:6/1/2010 9:13:00 AM

--  利用 cards.dll写自己的扑克程序
观察 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 方式编写的空当接龙源代码,大家如果有兴趣可以看看。




W 3 C h i n a ( since 2003 ) 旗 下 站 点
苏ICP备05006046号《全国人大常委会关于维护互联网安全的决定》《计算机信息网络国际联网安全保护管理办法》
62.500ms