您的位置:首页精文荟萃破解文章 → Win32 ASM详解 二十五 位图初步

Win32 ASM详解 二十五 位图初步

时间:2004/10/15 1:01:00来源:本站整理作者:蓝点我要评论(0)


在这一课,我们将学习怎样在程序中使用位图。 更准确地说,我们要学习的是怎样在一个窗口的客户区中显示位图。

 

理论

位图就是存贮于电脑中的图片。位图文件有相当多的格式(译者:如.BMP.JPG.GIF.PIC 等)但Windows仅 支持 Windows Bitmap Graphics 格式,即BMP文件。 本课所指的位图也是BMP文件。 使用位图最简单的方法就是把它定义在资源文件(.rc)中。 定义的方法有两种。第一种方法是把它定义为整数宏,具体如下:
 

#define IDB_MYBITMAP   100
IDB_MYBITMAP  BITMAP  "c:\project\example.bmp"

第一行我们定义了一个值为100的整数宏。 第二行我们把这个整数宏指向所要定义的位图, 这样,编译器就能知道位图所在的路径。
另一种方法是给它起一个名字,也就是把它定义为字符串,具体如下:

MyBitMap  BITMAP "c:\project\example.bmp"

两种方法效果是一样的。 选择哪一种方法,视乎在程序中你喜欢用整数宏还是用字符串来指向位图。
现在我们已经把位图定义在资源文件中,下一步就是把它显示在窗口的客户区上。

 

在程序中,我们使用API函数 LoadBitmap 取得位图句柄。 下面是 LoadBitmap 函数的 完型:

 

 

LoadBitmap proto hInstance:HINSTANCE, lpBitmapName:LPSTR

 


该函数返回一个位图句柄。函数有两个参数,其中 hInstance 是程序句柄。 lpBitmapName 是位图名字的指针(适用于第二种定义方法)。如果你使用了第一种 定义方法,你可以填入指向位图的值或整数宏 (对应上例这个值就是100,整数宏是IDB_MYBITMAP)。下面是简单的例子:

 

第一种方法:

 

.386
.model flat, stdcall
................
.const
IDB_MYBITMAP    equ 100
...............
.data?
hInstance  dd ?
..............
.code
.............
    invoke GetModuleHandle,NULL
    mov hInstance,eax
............
    invoke LoadBitmap,hInstance,IDB_MYBITMAP
...........

第二种方法:

.386
.model flat, stdcall
................
.data
BitmapName  db "MyBitMap",0
...............
.data?
hInstance  dd ?
..............
.code
.............
    invoke GetModuleHandle,NULL
    mov hInstance,eax
............
    invoke LoadBitmap,hInstance,addr BitmapName
...........

 

获得一个设备文本(DC)句柄。你可以在响应WM_PAINT消息时通过API函数BeginPaint获得。 如果在其它消息中则可以用API函数GetDC获得。

创建这个DC的内存映像。这样做的目的是建立一张“隐藏的画纸”,把位图 “画”在上面,作缓冲之用。完成这项工作后,我们就通过一个函数把“画纸”上的位图复制 到真正的DC中。这就是在屏幕上快速显示图象的双缓冲技术。(译者:可以减少图象抖动) 这张“画纸”用API函数 CreateCompatibleDC 建立,下面是它的完型:

 

 

CreateCompatibleDC  proto  hdc:HDC

 


如果函数执行成功,将返回DC内存映像也即“画纸”的句柄。

现在我们已经有了“画纸”,可以把位图画在上面了。这可以通过API函数 SelectObject 完成, 其中第一个参数是“画纸”的句柄,第二个参数则是位图的句柄,下面是函数的完型:

 

 

SelectObject   proto  hdc:HDC, hGdiObject:DWORD

 

现在位图已经画在“画纸”上了。下一步我们要把位图复制到真正的DC中。 有很多API函数都能完成这项工作,例如 BitBlt 和 StretchBlt。 函数 BitBlt 仅仅将一个DC的内容简单地复制到另一个DC中,而函数 StretchBlt 则能够自动调整源DC复制内容的大小已适应目的DC的输出区域大小,因此前者比后者速度更快。 在这里我们只使用函数 BitBlt ,下面是它的完型:

 

 

BitBlt  proto  hdcDest:DWORD, nxDest:DWORD, nyDest:DWORD, nWidth:DWORD, nHeight:DWORD, hdcSrc:DWORD, nxSrc:DWORD, nySrc:DWORD, dwROP:DWORD

 

hdcDest 目的DC的句柄。

 

nxDest, nyDest 目的DC输出区域的左上角坐标。

 

nWidth, nHeight 目的DC输出区域的长和宽。

 

hdcSrc 源DC的句柄。

 

nxSrc, nySrc 源DC中所要复制区域的左上角坐标。

 

dwROP 屏面运算码(ROP)。该参数用以确定复制内容的颜色与输出区域原来的颜色按哪种运算 方式处理。通常,只需要简单地用复制内容把输出区域覆盖掉。

 

一切办妥后,就用API函数 DeleteObject 释放位图对象,也就是把位图“抹掉”。

大功告成! 现在再来回顾一下整个过程:首先,你需要把位图定义在资源文件中。 然后,你需要在程序中载入位图资源,并取得位图句柄。随后,你需要获得位图输出区域的DC, 以及创建这个DC的内存映像,并把位图放进这个DC内存映像中。最后把位图从DC内存映像复制到 真正的DC中。

例子:

.386
.model flat,stdcall
option casemap:none
include \masm32\include\windows.inc
include \masm32\include\user32.inc
include \masm32\include\kernel32.inc
include \masm32\include\gdi32.inc
includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\gdi32.lib

WinMain proto :DWORD,:DWORD,:DWORD,:DWORD
IDB_MAIN   equ 1

.data
ClassName db "SimpleWin32ASMBitmapClass",0
AppName  db "Win32ASM Simple Bitmap Example",0

.data?
hInstance HINSTANCE ?
CommandLine LPSTR ?
hBitmap dd ?

.code
start:
 invoke GetModuleHandle, NULL
 mov    hInstance,eax
 invoke GetCommandLine
 mov    CommandLine,eax
 invoke WinMain, hInstance,NULL,CommandLine, SW_SHOWDEFAULT
 invoke ExitProcess,eax

WinMain proc hInst:HINSTANCE,hPrevInst:HINSTANCE,CmdLine:LPSTR,CmdShow:DWORD
 LOCAL wc:WNDCLASSEX
 LOCAL msg:MSG
 LOCAL hwnd:HWND
 mov   wc.cbSize,SIZEOF WNDCLASSEX
 mov   wc.style, CS_HREDRAW or CS_VREDRAW
 mov   wc.lpfnWndProc, OFFSET WndProc
 mov   wc.cbClsExtra,NULL
 mov   wc.cbWndExtra,NULL
 push  hInstance
 pop   wc.hInstance
 mov   wc.hbrBackground,COLOR_WINDOW+1
 mov   wc.lpszMenuName,NULL
 mov   wc.lpszClassName,OFFSET ClassName
 invoke LoadIcon,NULL,IDI_APPLICATION
 mov   wc.hIcon,eax
 mov   wc.hIconSm,eax
 invoke LoadCursor,NULL,IDC_ARROW
 mov   wc.hCursor,eax
 invoke RegisterClassEx, addr wc
 INVOKE CreateWindowEx,NULL,ADDR ClassName,ADDR AppName,\
           WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,\
           CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,NULL,NULL,\
           hInst,NULL
 mov   hwnd,eax
 invoke ShowWindow, hwnd,SW_SHOWNORMAL
 invoke UpdateWindow, hwnd
 .while TRUE
  invoke GetMessage, ADDR msg,NULL,0,0
  .break .if (!eax)
  invoke TranslateMessage, ADDR msg
  invoke DispatchMessage, ADDR msg
 .endw
 mov     eax,msg.wParam
 ret
WinMain endp

WndProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
   LOCAL ps:PAINTSTRUCT
   LOCAL hdc:HDC
   LOCAL hMemDC:HDC
   LOCAL rect:RECT
   .if uMsg==WM_CREATE
      invoke LoadBitmap,hInstance,IDB_MAIN
      mov hBitmap,eax
   .elseif uMsg==WM_PAINT
      invoke BeginPaint,hWnd,addr ps
      mov    hdc,eax
      invoke CreateCompatibleDC,hdc
      mov    hMemDC,eax
      invoke SelectObject,hMemDC,hBitmap
      invoke GetClientRect,hWnd,addr rect
      invoke BitBlt,hdc,0,0,rect.right,rect.bottom,hMemDC,0,0,SRCCOPY
      invoke DeleteDC,hMemDC
      invoke EndPaint,hWnd,addr ps
 .elseif uMsg==WM_DESTROY
  invoke DeleteObject,hBitmap
  invoke PostQuitMessage,NULL
 .ELSE
  invoke DefWindowProc,hWnd,uMsg,wParam,lParam
  ret
 .ENDIF
 xor eax,eax
 ret
WndProc endp
end start

;---------------------------------------------------------------------
;                            资源定义
;---------------------------------------------------------------------
#define IDB_MAIN 1
IDB_MAIN BITMAP "tweety78.bmp"

分析:


#define IDB_MAIN 1
IDB_MAIN BITMAP "tweety78.bmp"

定义整数宏IDB_MAIN的值为1,然后把它指向一个与资源文件处于相同目录文件名为“tweety.bmp"的位图。

   .if uMsg==WM_CREATE
      invoke LoadBitmap,hInstance,IDB_MAIN
      mov hBitmap,eax

在处理 WM_CREATE 消息时, 我们通过API函数 LoadBitmap 载入位图资源,并通过函数 返回值取得位图句柄。
然后,我们就可以把位图画在窗口客户区上。

   .elseif uMsg==WM_PAINT
      invoke BeginPaint,hWnd,addr ps
      mov    hdc,eax
      invoke CreateCompatibleDC,hdc
      mov    hMemDC,eax
      invoke SelectObject,hMemDC,hBitmap
      invoke GetClientRect,hWnd,addr rect
      invoke BitBlt,hdc,0,0,rect.right,rect.bottom,hMemDC,0,0,SRCCOPY
      invoke DeleteDC,hMemDC
      invoke EndPaint,hWnd,addr ps

在本例中,我们选用在响应WM_PAINT消息时画出位图。首先我们通过API函数l BeginPaint 获得窗口客户区的DC句柄。 接着我们通过API函数 CreateCompatibleDC 创建该DC 的内存映像,并通过API函数 SelectObject 把位图放进内存映像中。下一步,我们通过API函数 GetClientRect 取得窗口客户区的大小。最后,我们通过API函数 BitBlt 把位图从DC内存映像复制到真正的客户区DC中。 完成显示工作后,我们通过API函数 DeleteDC 释放DC内存映像,并用API函数 EndPaint 释放客户区DC, 结束画图工作。

 .elseif uMsg==WM_DESTROY
  invoke DeleteObject,hBitmap
  invoke PostQuitMessage,NULL

当我们不再需要位图时,通过API函数 DeleteObject 把它释放。







相关阅读 Windows错误代码大全 Windows错误代码查询激活windows有什么用Mac QQ和Windows QQ聊天记录怎么合并 Mac QQ和Windows QQ聊天记录Windows 10自动更新怎么关闭 如何关闭Windows 10自动更新windows 10 rs4快速预览版17017下载错误问题Win10秋季创意者更新16291更新了什么 win10 16291更新内容windows10秋季创意者更新时间 windows10秋季创意者更新内容kb3150513补丁更新了什么 Windows 10补丁kb3150513是什么

文章评论
发表评论

热门文章 去除winrar注册框方法

最新文章 比特币病毒怎么破解 比去除winrar注册框方法 华为无线路由器HG522-C破解教程(附超级密码JEB格式文件京东电子书下载和阅读限制破解教UltraISO注册码全集(最新)通过Access破解MSSQL获得数据

人气排行 华为无线路由器HG522-C破解教程(附超级密码JEB格式文件京东电子书下载和阅读限制破解教UltraISO注册码全集(最新)qq相册密码破解方法去除winrar注册框方法(适应任何版本)怎么用手机破解收费游戏华为无线猫HG522破解如何给软件脱壳基础教程