WIN32汇编语言中位图的使用

说到位图,我们其实很早就接触过,从最早接触计算机,我们应该就知道有图片这个东西,然后再进一步说,图片在电脑上有好几种格式比如jpg. gif .png.pcx.bmp等等,其中bmp格式的图片文件其实就是位图(windows的说法是DIB),位图文件也分为几种(因为存储的位置不同)。因为在学的是罗云斌老师的书籍,这次依旧还拿他老人家的程序学习,拓展创新,学为己用,毕竟还不是老手,一步一步走才可以。

了解了位图是什么东西,下面总结一下制作一个能显示位图的时钟的大体流程:

资源脚本文件
 1.创建资源工程                           20.c                      
2.添加资源 位图,图标,光标
3.编译资源脚本 生成20.resc文件

GDI操作

1.画线    时钟指针                       
2.画图 钟面,背景,边框,椭圆小点
窗口操作
1.与时钟有关的计算 半径,圆心,刻度位置等
2.时钟的初始化 设置时钟刚出来时的状态等
3.窗口过程 对于不同的消息的处理操作
4.注册窗口类 主要是一些自定义的窗口属性
5.创建并显示窗口 主要包括窗口的显示状态等
6.消息循环 窗口核心

上面总体给这个程序来了一个描述,下面来详细介绍一下,以及记录一下学习的时候遇见的一些问题和自己的一些心得体会。

首先我们来创建资源文件,同样我依旧是用的ResEdit,经常用了,已经习惯了,看个人口味了,这个无所谓,都是一样的,这次因为不需要使用通常所用的显式的菜单以及对话框,子控件等资源,因此看起来资源脚本的代码量很好少,只需添加创建好的位图文件,图标文件,光标文件即可我写的资源代码如下:

// Generated by ResEdit 1.6.6

// Copyright (C) 2006-2015

// http://www.resedit.net

#include <windows.h>

#include <commctrl.h>

#include <richedit.h>

#define IDB_CIRCLE2                             115

#define IDB_BACK1                               120

#define IDB_BACK2                               117

#define IDB_CIRCLE1                             118

#define IDB_MASK1                               119

#define IDB_MASK2                               116

#define ICO_MAIN                                121

#define IDC_MOVE                                122

#define IDC_MAIN                                123

//

// Bitmap resources

//

LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL

IDB_BACK1          BITMAP         ".\\Back1.bmp"

LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL

IDB_BACK2          BITMAP         ".\\Back2.bmp"

LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL

IDB_CIRCLE1        BITMAP         ".\\Circle1.bmp"

LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL

IDB_CIRCLE2        BITMAP         ".\\Circle2.bmp"

LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL

IDB_MASK1          BITMAP         ".\\Mask1.bmp"

LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL

IDB_MASK2          BITMAP         ".\\Mask2.bmp"

//

// Cursor resources

//

LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL

IDC_MOVE           CURSOR         ".\\Move.cur"

LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL

IDC_MAIN           CURSOR         ".\\Main.cur"

//

// Icon resources

//

LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL

ICO_MAIN           ICON           ".\\Main.ico"

关于资源文件有一点需要注意,就是在编写资源脚本文件的时候当你添加某个资源项的时候,都会对应有一个对应的ID值,就像是子控件的控件ID一样,虽然在编译资源是右边的选项栏里面没有显示,但是,当你把资源文件写完的时候,在ResEdit安装目录下含自己创建的工程名字的文件夹在该文件夹下有关于资源中用到的文件,其中有一个resource.h的.h文件,我们可以以文档的形式打开,发现其中是一些定义好宏定义,生明了某个资源名字对应的INT型数值,对于这个数值,一般的程序来说其先后顺序,以及数值的大小都没有什么严格的要求,但是本次程序,当你在写程序实现代码的时候就会发现,有4个位图资源的ID数值是有特殊要求的,如下

#define IDB_CIRCLE2                             115

#define IDB_MASK2                               116

#define IDB_CIRCLE1                             118

#define IDB_MASK1                               119

你如果总体去看资源文件的话也许不会发现什么但是把这四个单拉出来你就会发现,IDB_CIRCLE2 与IDB_MASK2       的定义的INT型数值ID分别为115,116。    115+1=116.     

然后看 IDB_CIRCLE1 与IDB_MASK1 的INT型数值ID分别为  118,119,   118+1=119,也就是说IDM_CIRCLE(1,2)+1=IDM_MASK(1,2)(通俗的说), 为什么要这样呢(其实我在运行完程序之后才明白的,,刚开始也不知道其中的用意),下面来看一下20.asm中的一段相关代码:

_CreateBackGround    proc

LOCAL @hDc,@hDcCircle,@hDcMask

LOCAL @hBmpBack,@hBmpCircle,@hBmpMask

invoke    GetDC,hWinMain

mov       @hDc,eax

invoke    CreateCompatibleDC,@hDc

mov       hDcBack,eax

invoke    CreateCompatibleDC,@hDc

mov       hDcClock,eax

invoke    CreateCompatibleDC,@hDc

mov       @hDcCircle,eax

invoke    CreateCompatibleDC,@hDc

mov       @hDcMask,eax

invoke    CreateCompatibleBitmap,@hDc,CLOCK_SIZE,CLOCK_SIZE

mov       hBmpBack,eax

invoke    CreateCompatibleBitmap,@hDc,CLOCK_SIZE,CLOCK_SIZE

mov       hBmpClock,eax

invoke    ReleaseDC,hWinMain,@hDc

invoke    LoadBitmap,hInstance,dwNowBack

mov       @hBmpBack,eax

invoke    LoadBitmap,hInstance,dwNowCircle

mov       @hBmpCircle,eax

mov       eax,dwNowCircle

inc       eax                                                  ;注意此处

invoke    LoadBitmap,hInstance,eax

mov       @hBmpMask,eax

如上面代码是_CreateBackGround 子函数的一部分,在标有注释的地方,有一句 代码:

mov       eax,dwNowCircle

        inc       eax     

dwNowCircle是一个全局变量。在_ProcWinMain 子函数中处理COMMAND消息的时候有这样的几句代码:

.elseif
eax == WM_COMMAND

mov eax,wParam

.if ax ==
IDM_BACK1

mov dwNowBack,IDB_BACK1                         ;注意dwNowBack的值

invoke
CheckMenuRadioItem,hMenu,IDM_BACK1,IDM_BACK2,IDM_BACK1,NULL

.elseif
ax == IDM_BACK2

mov dwNowBack,IDB_BACK2                          ;注意dwNowBack的值

invoke
CheckMenuRadioItem,hMenu,IDM_BACK1,IDM_BACK2,IDM_BACK2,NULL

.elseif
ax == IDM_CIRCLE1

mov dwNowCircle,IDB_CIRCLE1                      ;注意dwNowCircle的值

invoke
CheckMenuRadioItem,hMenu,IDM_CIRCLE1,IDM_CIRCLE2,IDM_CIRCLE1,NULL

.elseif
ax == IDM_CIRCLE2

mov dwNowCircle,IDB_CIRCLE2                       ;注意dwNowCircle的值

invoke
CheckMenuRadioItem,hMenu,IDM_CIRCLE1,IDM_CIRCLE2,IDM_CIRCLE2,NULL

.elseif
ax == IDM_EXIT

call _Quit

xor eax,eax

ret

.endif

invoke
_DeleteBackGround

invoke
_CreateBackGround                                              已经对dwNowBack或者dwNowCircle赋值,然后调用子函数。

invoke
_CreateClockPic

注意上面标有注释的地方,意思就是当收到COMMAND消息的时候,如果消息内容是按下某个选项触发的,那么就把这个选项的ID值赋值给全局变量dwNowBack或者dwNowCircle,假如说当这个选项是IDM_CIRCLE1或者IDM_CIRCLE2的时候,dwNowCircle的值就是118或115,此时再看_CreateBackGround子函数中作注释的代码,就会发现“inc
dwNowCircle”  之后dwNowCircle的值就变为相应的119或者116 ,此时你再对照程序开头声明的等值或者资源文件的宏定义,会发现,IDB_MASK1与IDB_MASK2的int型ID数值为
  119与116,也就是说经过“inc dwNowCircle” 这句代码之后,dwNowCircle的值就是IDB_MASK1或者IDB_MASK2的值,代表的就是遮掩图片的ID。关于这个问题刚开始我也是很纠结,后来才明白(对于这个方式我感觉还是很陌生的,我感觉倒不如用MOV指令,毕竟我是新手,估计那样会开销比较大,)。

下面来具体看一下程序代码:

.386

.model flat, stdcall

option casemap :none

include windows.inc

include user32.inc

includelib user32.lib

include kernel32.inc

includelib kernel32.lib

include Gdi32.inc

includelib Gdi32.lib

CLOCK_SIZE equ
150

ICO_MAIN equ
121

IDC_MAIN equ
123

IDC_MOVE equ
122

IDB_BACK1 equ
120

IDB_CIRCLE1 equ
118     ;;注意Circle1的ID值必须是加一后等于MASK1的ID值,不然不会成功。

IDB_MASK1 equ
119

IDB_BACK2 equ
117

IDB_CIRCLE2 equ
115      ;注意Circle2的ID值必须是加一后等于MASK2的ID值,不然不会成功。

IDB_MASK2 equ
116

ID_TIMER equ
1

IDM_BACK1 equ
100

IDM_BACK2 equ
101

IDM_CIRCLE1 equ
102

IDM_CIRCLE2 equ
103

IDM_EXIT equ
104

.data?

hInstance dd
?

hWinMain dd
?

hCursorMove dd
? ;Cursor when move

hCursorMain dd
? ;Cursor when normal

hMenu dd
?

hBmpBack dd
?

hDcBack dd
?

hBmpClock dd
?

hDcClock dd
?

dwNowBack dd
?

dwNowCircle dd
?

.const

szClassName db
‘Clock‘,0

dwPara180 dw
180

dwRadius dw
CLOCK_SIZE/2

szMenuBack1 db
‘使用格子背景(&A)‘,0

szMenuBack2 db
‘使用花布背景(&B)‘,0

szMenuCircle1 db
‘使用淡蓝色边框(&C)‘,0

szMenuCircle2 db
‘使用粉红色边框(&D)‘,0

szMenuExit db
‘退出(&X)...‘,0

.code

_CalcX proc
_dwDegree,_dwRadius

LOCAL @dwReturn

fild dwRadius

fild _dwDegree

fldpi

fmul ;角度*Pi

fild dwPara180

fdivp st(1),st
;角度*Pi/180

fsin ;Sin(角度*Pi/180)

fild _dwRadius

fmul ;半径*Sin(角度*Pi/180)

fadd ;X+半径*Sin(角度*Pi/180)

fistp @dwReturn

mov eax,@dwReturn

ret

_CalcX endp

_CalcY proc
_dwDegree,_dwRadius

LOCAL @dwReturn

fild dwRadius

fild _dwDegree

fldpi

fmul

fild dwPara180

fdivp st(1),st

fcos

fild _dwRadius

fmul

fsubp st(1),st

fistp @dwReturn

mov eax,@dwReturn

ret

_CalcY endp

_DrawLine proc
_hDC,_dwDegree,_dwRadius

LOCAL @dwX1,@dwY1,@dwX2,@dwY2

invoke
_CalcX,_dwDegree,_dwRadius

mov @dwX1,eax

invoke
_CalcY,_dwDegree,_dwRadius

mov @dwY1,eax

add _dwDegree,180

invoke
_CalcX,_dwDegree,10

mov @dwX2,eax

invoke
_CalcY,_dwDegree,10

mov @dwY2,eax

invoke
MoveToEx,_hDC,@dwX1,@dwY1,NULL

invoke
LineTo,_hDC,@dwX2,@dwY2

ret

_DrawLine endp

_CreateClockPic proc

LOCAL @stTime:SYSTEMTIME

pushad

invoke
BitBlt,hDcClock,0,0,CLOCK_SIZE,CLOCK_SIZE,hDcBack,0,0,SRCCOPY

invoke
GetLocalTime,addr @stTime

invoke
CreatePen,PS_SOLID,1,0

invoke
SelectObject,hDcClock,eax

invoke
DeleteObject,eax

movzx eax,@stTime.wSecond

mov ecx,360/60

mul ecx
;秒针度数 = 秒 * 360/60

invoke
_DrawLine,hDcClock,eax,60

invoke
CreatePen,PS_SOLID,2,0

invoke
SelectObject,hDcClock,eax

invoke
DeleteObject,eax

movzx eax,@stTime.wMinute

mov ecx,360/60

mul ecx
;分针度数 = 分 * 360/60

invoke
_DrawLine,hDcClock,eax,55

invoke
CreatePen,PS_SOLID,3,0

invoke
SelectObject,hDcClock,eax

invoke
DeleteObject,eax

movzx eax,@stTime.wHour

.if eax >= 12

sub eax,12

.endif

mov ecx,360/12

mul ecx

movzx ecx,@stTime.wMinute

shr ecx,1

add eax,ecx

invoke
_DrawLine,hDcClock,eax,50

invoke
GetStockObject,NULL_PEN

invoke
SelectObject,hDcClock,eax

invoke
DeleteObject,eax

popad

ret

_CreateClockPic endp

_CreateBackGround    proc

LOCAL @hDc,@hDcCircle,@hDcMask

LOCAL @hBmpBack,@hBmpCircle,@hBmpMask

invoke    GetDC,hWinMain

mov       @hDc,eax

invoke    CreateCompatibleDC,@hDc

mov       hDcBack,eax

invoke    CreateCompatibleDC,@hDc

mov       hDcClock,eax

invoke    CreateCompatibleDC,@hDc

mov       @hDcCircle,eax

invoke    CreateCompatibleDC,@hDc

mov       @hDcMask,eax

invoke    CreateCompatibleBitmap,@hDc,CLOCK_SIZE,CLOCK_SIZE

mov       hBmpBack,eax

invoke    CreateCompatibleBitmap,@hDc,CLOCK_SIZE,CLOCK_SIZE

mov       hBmpClock,eax

invoke    ReleaseDC,hWinMain,@hDc

invoke    LoadBitmap,hInstance,dwNowBack

mov       @hBmpBack,eax

invoke    LoadBitmap,hInstance,dwNowCircle

mov       @hBmpCircle,eax

mov       eax,dwNowCircle

inc       eax

invoke    LoadBitmap,hInstance,eax

mov       @hBmpMask,eax

invoke    SelectObject,hDcBack,hBmpBack

invoke    SelectObject,hDcClock,hBmpClock

invoke    SelectObject,@hDcCircle,@hBmpCircle

invoke    SelectObject,@hDcMask,@hBmpMask

invoke    CreatePatternBrush,@hBmpBack                  ;格子背景

push      eax

invoke    SelectObject,hDcBack,eax

invoke    PatBlt,hDcBack,0,0,CLOCK_SIZE,CLOCK_SIZE,PATCOPY

invoke    DeleteObject,eax

invoke    BitBlt,hDcBack,0,0,CLOCK_SIZE,CLOCK_SIZE,@hDcMask,0,0,SRCAND         ;利用遮掩图片和ROP码画时钟边框(淡蓝色边框)

invoke    BitBlt,hDcBack,0,0,CLOCK_SIZE,CLOCK_SIZE,@hDcCircle,0,0,SRCPAINT

invoke    DeleteDC,@hDcCircle

invoke    DeleteDC,@hDcMask

invoke    DeleteObject,@hBmpBack

invoke    DeleteObject,@hBmpCircle

invoke    DeleteObject,@hBmpMask

ret

_CreateBackGround endp

_DeleteBackGround proc

invoke DeleteDC,hDcBack

invoke DeleteDC,hDcClock

invoke DeleteObject,hBmpBack

invoke DeleteObject,hBmpClock

ret

_DeleteBackGround endp

_Quit proc

invoke
KillTimer,hWinMain,ID_TIMER

invoke
DestroyWindow,hWinMain

invoke
PostQuitMessage,NULL

invoke
_DeleteBackGround

invoke
DestroyMenu,hMenu

ret

_Quit endp

_Init           proc

LOCAL   @hBmpBack,@hBmpCircle

invoke  CreatePopupMenu

mov  hMenu,eax

invoke  AppendMenu,hMenu,0,IDM_BACK1,offset szMenuBack1

invoke  AppendMenu,hMenu,0,IDM_BACK2,offset szMenuBack2

invoke  AppendMenu,hMenu,MF_SEPARATOR,0,NULL

invoke  AppendMenu,hMenu,0,IDM_CIRCLE1,offset szMenuCircle1

invoke  AppendMenu,hMenu,0,IDM_CIRCLE2,offset szMenuCircle2

invoke  AppendMenu,hMenu,MF_SEPARATOR,0,NULL

invoke  AppendMenu,hMenu,0,IDM_EXIT,offset szMenuExit

invoke  CheckMenuRadioItem,hMenu,IDM_CIRCLE1,IDM_CIRCLE2,IDM_CIRCLE1,NULL

invoke  CheckMenuRadioItem,hMenu,IDM_BACK1,IDM_BACK2,IDM_BACK1,NULL

invoke  CreateEllipticRgn,0,0,CLOCK_SIZE+1,CLOCK_SIZE+1

push    eax

invoke  SetWindowRgn,hWinMain,eax,TRUE

pop     eax

invoke  DeleteObject,eax

invoke  SetWindowPos,hWinMain,HWND_TOPMOST,0,0,0,0,SWP_NOMOVE or SWP_NOSIZE

mov     dwNowBack,IDB_BACK1

mov     dwNowCircle,IDB_CIRCLE1

invoke  _CreateBackGround

invoke  _CreateClockPic

invoke  SetTimer,hWinMain,ID_TIMER,1000,NULL

ret

_Init endp

_ProcWinMain    proc    uses ebx edi esi hWnd,uMsg,wParam,lParam

LOCAL   @stPS:PAINTSTRUCT

LOCAL   @hDC

LOCAL   @stPos:POINT

mov     eax,uMsg

.if     eax ==  WM_TIMER

invoke  _CreateClockPic

invoke  InvalidateRect,hWnd,NULL,FALSE

.elseif eax ==  WM_PAINT

invoke  BeginPaint,hWnd,addr @stPS

mov     @hDC,eax

mov     eax,@stPS.rcPaint.right

sub     eax,@stPS.rcPaint.left

mov     ecx,@stPS.rcPaint.bottom

sub     ecx,@stPS.rcPaint.top

invoke  BitBlt,@hDC,@stPS.rcPaint.left,@stPS.rcPaint.top,eax,ecx,hDcClock,@stPS.rcPaint.left,\

@stPS.rcPaint.top,SRCCOPY

invoke  EndPaint,hWnd,addr @stPS

.elseif
eax == WM_CREATE

mov eax,hWnd

mov hWinMain,eax

invoke
_Init

.elseif
eax == WM_COMMAND

mov eax,wParam

.if ax ==
IDM_BACK1

mov dwNowBack,IDB_BACK1

invoke
CheckMenuRadioItem,hMenu,IDM_BACK1,IDM_BACK2,IDM_BACK1,NULL

.elseif
ax == IDM_BACK2

mov dwNowBack,IDB_BACK2

invoke
CheckMenuRadioItem,hMenu,IDM_BACK1,IDM_BACK2,IDM_BACK2,NULL

.elseif
ax == IDM_CIRCLE1

mov dwNowCircle,IDB_CIRCLE1

invoke
CheckMenuRadioItem,hMenu,IDM_CIRCLE1,IDM_CIRCLE2,IDM_CIRCLE1,NULL

.elseif
ax == IDM_CIRCLE2

mov dwNowCircle,IDB_CIRCLE2

invoke
CheckMenuRadioItem,hMenu,IDM_CIRCLE1,IDM_CIRCLE2,IDM_CIRCLE2,NULL

.elseif
ax == IDM_EXIT

call _Quit

xor eax,eax

ret

.endif

invoke
_DeleteBackGround

invoke
_CreateBackGround

invoke
_CreateClockPic

invoke
InvalidateRect,hWnd,NULL,FALSE

.elseif
eax == WM_CLOSE

call _Quit

.elseif eax == WM_RBUTTONDOWN

invoke
GetCursorPos,addr @stPos

invoke
TrackPopupMenu,hMenu,TPM_LEFTALIGN,@stPos.x,@stPos.y,NULL,hWnd,NULL

.elseif eax ==
WM_LBUTTONDOWN

invoke
SetCursor,hCursorMove

invoke
UpdateWindow,hWnd

invoke
ReleaseCapture

invoke
SendMessage,hWnd,WM_NCLBUTTONDOWN,HTCAPTION,0

invoke
SetCursor,hCursorMain

.else

invoke
DefWindowProc,hWnd,uMsg,wParam,lParam

ret

.endif

xor eax,eax

ret

_ProcWinMain endp

_WinMain proc

LOCAL @stWndClass:WNDCLASSEX

LOCAL @stMsg:MSG

invoke
GetModuleHandle,NULL

mov hInstance,eax

invoke
LoadCursor,hInstance,IDC_MOVE

mov hCursorMove,eax

invoke
LoadCursor,hInstance,IDC_MAIN

mov hCursorMain,eax

invoke
RtlZeroMemory,addr @stWndClass,sizeof @stWndClass

invoke
LoadIcon,hInstance,ICO_MAIN

mov @stWndClass.hIcon,eax

mov @stWndClass.hIconSm,eax

push hCursorMain

pop @stWndClass.hCursor

push hInstance

pop @stWndClass.hInstance

mov @stWndClass.cbSize,sizeof WNDCLASSEX

mov @stWndClass.style,CS_HREDRAW or CS_VREDRAW

mov @stWndClass.lpfnWndProc,offset _ProcWinMain

mov @stWndClass.hbrBackground,COLOR_WINDOW + 1

mov @stWndClass.lpszClassName,offset szClassName

invoke
RegisterClassEx,addr @stWndClass

invoke
CreateWindowEx,NULL,\

offset szClassName,offset szClassName,\

WS_POPUP or WS_SYSMENU,\

100,100,CLOCK_SIZE,CLOCK_SIZE,\

NULL,NULL,hInstance,NULL

mov hWinMain,eax

invoke
ShowWindow,hWinMain,SW_SHOWNORMAL

invoke
UpdateWindow,hWinMain

.while
TRUE

invoke
GetMessage,addr @stMsg,NULL,0,0

.break
.if eax == 0

invoke
TranslateMessage,addr @stMsg

invoke
DispatchMessage,addr @stMsg

.endw

ret

_WinMain endp

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

start:

call _WinMain

invoke
ExitProcess,NULL

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

end start

代码量确实有点长(相比其他语言来说...),因为这次的代码有一部分和上次的程序代码(上次写的WIN32时钟博客)有相同的操作,不再做总结,剩下的一部分需要注意的就是创建背景与时钟框(_CreateBackGround)与时钟的初始化(_Init)了,在创建背景的时候,很简单利用两个自定义的画刷将整个钟面背景填充作为背景,有意思的是对时钟框的操作,要将时钟框画到钟面上去,本程序中利用的是BitBlt()数据块传送函数,其实就是把某个已经制作好的时钟框(提前制作好的位图文件)拷贝到指定的区域,当然如果是要拷贝的话,就要利用到ROP码(其实就是源像素与目标像素的结合方式)了,由于做好的时钟框像素不是直接替换目标背景的像素,而是叠加到目标像素,因为黑色的颜色值为0,任何一种颜色与黑色进行OR操作都会是原来的颜色,不会改变,ROP码SRCPAINT就是将目标像素与源像素进行OR运算,所以首先将源像素与提前写好的MASK遮掩图片进行and操作(ROP码为SRCAND)将相应的位置与黑色叠加,然后再将源时钟框像素传送到目标时钟框,采用OR(ROP码为SRCPAINT)的操作,这样一个可以切换的时钟边框才能正常地显示出来。这也是本程序我感觉当时很不好理解的一个地方。

下面就是关于时钟的初始化(_Init子函数),对于初始化,我的理解就是当时钟刚开始显示出来没有任何操作的时候显示的状态(包括一个弹出的窗口和背景,时钟框,形状等)

在写程序的时候我也出现了一个很低级的错误,在每个子函数结束之前总会有一个ret指令,这个以前在学DOS汇编的时候就应该已经知道了,它的意思就是:当某一行代码调用子函数的时候记住这一行代码的下一句代码的位置,当子函数调用完成之后,在返回到这个位置继续执行,(我感觉就像是push  eip,  再pop   eip一样),代码分析到此结束。

下面来介绍本次程序用到的一些常用的API函数:

CreateComPatibleDC()

功能:

该函数创建一个与指定设备兼容的内存设备上下文环境(DC)。通过GetDc()获取的HDC直接与相关设备沟通,而本函数创建的DC,则是与内存中的一个表面相关联。

原型:

HDC CreateCompatibleDC(HDC hdc)

参数:

现有设备上下文环境的句柄,如果该句柄NULL,该函数创建一个与应用程序的当前显示器兼容的内存设备上下文环境

返回值:

如果成功,则返回内存设备上下文环境的句柄;如果失败,则返回值为NULL。

CreateComPatibleBitMap()

功能:

该函数创建与指定的设备环境相关的设备兼容的位图。

原型:

HBITMAP
CreateCompatibleBitmap(HDC hdc,int nWidth,int nHeight);

参数:

hdc:
设备环境句柄。

nWidth:指定位图的宽度,单位为像素。

nHeight:指定位图的高度,单位为像素。

返回值:

如果函数执行成功,那么返回值是位图的句柄;如果函数执行失败,那么返回值为NULL。

CreatePatternBrush()

功能:

该函数可以创建具有指定位图模式的逻辑刷子,该位图不能是DIB类型的位图,DIB位图是由CreateDIBSection函数创建的。

原型:

HBRUSH CreatePatternBrush(hbitmap)

参数:

hbitmap:指向用于创建逻辑刷子的位图

返回值:

如果该函数执行成功,那么返回值标识为一个逻辑刷子,如果该函数执行失败,那么返回值为NULL。

PatBlt()

功能:

该函数使用当前选入指定设备环境中的刷子绘制给定的矩形区域。通过使用给出的光栅操作来对该刷子的颜色和表面颜色进行组合。

原型:

BOOL
PatBlt(HDC hdc, int nXLeft, int nYLeft, int nWidth, int nHeight, DWORD dwRop);

参数:

hdc:设备环境句柄。

nXLeft:指定要填充的矩形左上角的X轴坐标,坐标按逻辑单位表示。

nYLeft:指定要填充的矩形左上角的Y轴坐标,坐标按逻辑单位表示。

nWidth:指定矩形的宽度,按逻辑单位表示宽度。

nHeight:指定矩形的高度,按逻辑单位表示高度。

dwRop:指定光栅操作码。该操作码可以取下列值,这些值的含义如下:

PATCOPY:将指定的模式拷贝到目标位图中。

PATINVERT:使用布尔XOR(异或)操作符将指定模式的颜色与目标矩形的颜色进行组合。

DSTINVERT:将目标矩形反向。

BLACKNESS:使用物理调色板中与索引0相关的颜色填充目标矩形。(对于缺省的物理调色板而言,该颜色为黑色)。

WHITENESS:使用物理调色板中与索引1有关的颜色来填充目标矩形。(对于缺省的物理调色板而言,该颜色为白色)。

返回值:

如果函数执行成功,则返回值为非零;如果函数执行失败,则返回值为0。

CreateElliPticRgn()

功能参数:

创建一个椭圆区域, (注:_In_ 表示该参数为输入参数)

x1

指定椭圆外接矩形左上角的逻辑横坐标。

y1

指定椭圆外接矩形左上角的逻辑纵坐标。

x2

指定椭圆外接矩形右下角的逻辑横坐标。

y2

指定椭圆外接矩形右下角的逻辑纵坐标。

原型:

HRGN CreateEllipticRgn( _In_ int nLeftRect, _In_ int nTopRect, _In_ int nRightRect, _In_ int nBottomRect)

返回值:

操作成功返回该区域的句柄,否则为NULL。

SetWindowRgn()

功能:

函数是设置了一个窗口的区域.只有被包含在这个区域内的地方才会被重绘,而不包含在区域内的其他区域系统将不会显示.

原型:

int SetWindowRgn(HWND hWnd, HRGN hRgn, BOOL bRedraw);

int SetWindowRgn(HRGN hRgn,BOOL bRedraw);

参数:

hWnd:窗口的句柄

hRgn:

指向的区域.函数起作用后将把窗体变成这个区域的形状.

如果这个参数是空值,窗体区域也会被设置成空值,也就是什么也看不到.

返回值:

如果函数执行成功,就返回非零的数字.如果失败,就返回零

GetWindowRgn()

功能:

获取窗口的区域,只有被包含在这个区域内的地方才会被重绘,而不包含在区域内的其他区域系统将不会显示

原型:

int GetWindowRgn(HWND hWnd, HRGN hRgn);

参数:

hWnd:窗口的句柄

hRgn:指向的区域

返回值:

返回值指定函数获取区域的类型。 它可以是下列值之一:

  • NULLREGION 该区域为空。
  • SIMPLEREGION 该区域是一个矩形。
  • COMPLEXREGION 该区域是多个矩形。
  • ERROR 错误发生;该区域不受影响。

SetCursor()

功能:

该函数确定光标的形状

原型:

HCURSOR
SetCursor(HCURSOR hCursor);

参数:

hCursor:光标的句柄,该光标由CreateCursor函数载入。如果该参数为NULL,则该光标从屏幕上移开。在Windows95中该光标的宽和高是GetSystemMetrics
函数的返回值SM_CXCURSOR和SM_CYCURSOR,并且光标的位深必须和显示器的位深相匹配,或者光标是单色的。

返回值:

如果有前一个光标,则返回值是前光标的句柄;如果没有前光标,则返回值是NULL。

ReleaseCapture()

功能:

函数功能是该函数从当前线程中的窗口释放鼠标捕获,并恢复通常的鼠标输入处理

原型:

BOOL
ReleaseCapture(VOlD)

参数:

返回值:

如果函数调用成功,返回非零值;如果函数调用失败,返回值是零。

TransparentBlt()

功能:

该函数对指定的源设备环境中的矩形区域像素的颜色数据进行位块(bit_block)转换,并将结果置于目标设备环境。

原型:

BOOL
TransparentBlt(HDC hdcDest, int nXOriginDest, int nYOriginDest, int nWidthDest, int hHeightDest, HDC hdcSrc, int nXOriginSrc, int nYOriginSrc, int nWidthSrc, int nHeightSrc, UINT crTransparent);

参数:

nXOriginDest:指定目标矩形左上角的X轴坐标,坐标以逻辑单位表示。

nYOriginDest:指定目标矩形左上角的Y轴坐标,坐标以逻辑单位表示。

nHeightDest:指定目标矩形的高度。

nXOriginSrc:指定源矩形(左上角)的X轴坐标,坐标以逻辑单位表示。

nYOriginsrc:指定源矩形(左上角)的Y轴坐标,坐标以逻辑单位表示。

nWidthSrc:指定源矩形的宽度。

nHeightSrc:指定源矩形的高度。

crTransparent:源 位图中的RGB值当作透明颜色。(用RGB(0,0,0)也就是黑色不行)

返回值:

如果函数执行成功,那么返回值为TRUE;如果函数执行失败,那么返回值为FALSE

SetwindowPos()

功能:

改变一个子窗口,弹出式窗口或顶层窗口的尺寸,位置和Z序。子窗口,弹出式窗口,及顶层窗口根据它们在屏幕上出现的顺序排序、顶层窗口设置的级别最高,并且被设置为Z序的第一个窗口。

原型:

WINUSERAPI BOOL WINAPI SetWindowPos(HWND hWnd,HWND hWndInsertAfter,int X,int Y,int cx,_In_ int cy, UINTuFlags);

参数:

pWndInsertAfter

用于标识在z-顺序的此 CWnd 对象之前的 CWnd 对象。

hWndlnsertAfter

在z序中的位于被置位的窗口前的窗口句柄。该参数必须为一个窗口句柄,或下列值之一:

  • HWND_BOTTOM:将窗口置于Z序的底部。如果参数hWnd标识了一个顶层窗口,则窗口失去顶级位置,并且被置在其他窗口的底部。
  • HWND_NOTOPMOST:将窗口置于所有非顶层窗口之上(即在所有顶层窗口之后)。如果窗口已经是非顶层窗口则该标志不起作用。
  • HWND_TOP:将窗口置于Z序的顶部。
  • HWND_TOPMOST:将窗口置于所有非顶层窗口之上。即使窗口未被激活窗口也将保持顶级位置。

查看该参数的使用方法,请看说明部分。

x

以客户坐标指定窗口新位置的左边界。

Y

以客户坐标指定窗口新位置的顶边界。

cx

以像素指定窗口的新的宽度。

cy

以像素指定窗口的新的高度。

uFlags

窗口尺寸和定位的标志。该参数可以是下列值的组合:

  1. SWP_ASYNCWINDOWPOS:如果调用进程不拥有窗口,系统会向拥有窗口的线程发出需求。这就防止调用线程在其他线程处理需求的时候发生死锁。
  2. SWP_DEFERERASE:防止产生WM_SYNCPAINT消息。
  3. SWP_DRAWFRAME:在窗口周围画一个边框(定义在窗口类描述中)。
  4. SWP_FRAMECHANGED:给窗口发送WM_NCCALCSIZE消息,即使窗口尺寸没有改变也会发送该消息。如果未指定这个标志,只有在改变了窗口尺寸时才发送WM_NCCALCSIZE。
  5. SWP_HIDEWINDOW;隐藏窗口。
  6. SWP_NOACTIVATE:不激活窗口。如果未设置标志,则窗口被激活,并被设置到其他最高级窗口或非最高级组的顶部(根据参数hWndlnsertAfter设置)。
  7. SWP_NOCOPYBITS:清除客户区的所有内容。如果未设置该标志,客户区的有效内容被保存并且在窗口尺寸更新和重定位后拷贝回客户区。
  8. SWP_NOMOVE:维持当前位置(忽略X和Y参数)。
  9. SWP_NOOWNERZORDER:不改变z序中的所有者窗口的位置。
  10. SWP_NOREDRAW:不重画改变的内容。如果设置了这个标志,则不发生任何重画动作。适用于客户区和非客户区(包括标题栏和滚动条)和任何由于窗回移动而露出的父窗口的所有部分。如果设置了这个标志,应用程序必须明确地使窗口无效并区重画窗口的任何部分和父窗口需要重画的部分。
  11. SWP_NOREPOSITION:与SWP_NOOWNERZORDER标志相同。
  12. SWP_NOSENDCHANGING:防止窗口接收WM_WINDOWPOSCHANGING消息。
  13. SWP_NOSIZE:维持当前尺寸(忽略cx和Cy参数)。
  14. SWP_NOZORDER:维持当前Z序(忽略hWndlnsertAfter参数)。
  15. SWP_SHOWWINDOW:显示窗口。

返回值:

如果函数成功,返回值为非零;如果函数失败,返回值为零

CreatepopupMenu()

功能:

创建一个下拉式菜单、子菜单或快捷菜单。此菜单最初是空的,但可用函数InsertMenultem来插入或追加菜单项。也可用函数InsertMenu来插入菜单项,用AppendMenu来追加菜单项。

原型:

HMENU
CreatePopupMenu(VOID)

参数:

返回值:

如果函数调用成功,返回值是新创建菜单的句柄。如果函数调用失败,返回值是NULL。

时间: 2024-11-01 11:03:08

WIN32汇编语言中位图的使用的相关文章

Win32编程中如何处理控制台消息

这篇文章讨论如何处理所有的控制台消息. 第一步,首先要安装一个事件钩子,也就是说要建立一个回调函数.调用Win32 API,原型如下: BOOL SetConsoleCtrlHandler(PHANDLER_ROUTINE HandlerRoutine, // 回调函数BOOL Add // 表示添加还是删除): 参数HandlerRoutine是一个指向函数的指针,原型如下: BOOL WINAPI HandlerRoutine(DWORD dwCtrlType // 控制事件类型): 所有的

使用AllocConsole在Win32程序中调用控制台调试输出

近期一个Win32窗口项目中,调试时经常需要输出调试信息以追踪数据流及程序运行状态. 起初我封装了一系列文件操作,实现了日志形式的调试信息输出,但在后期的使用过程中越发觉得颇不顺手.那么,如何方便地在Win32程序中使用控制台进行调试输出?答案如题:AllocConsole函数和C-Runtime的freopen函数.具体操作流程如下: 打开控制台 重定向输出流至控制台 执行调试信息输出操作 完整代码如下: SetConsoleTitle(_T("Debug Output")); fr

linux平台学x86汇编(十六):在汇编语言中调用C库函数

[版权声明:尊重原创,转载请保留出处:blog.csdn.net/shallnet,文章仅供学习交流,请勿用于商业用途] 其实在汇编语言中也是可以使用C库函数的,这一节我们来看一下如何在汇编语言中调用C库函数以使得我们的程序看上去很方便地和用户交互. C库包括C程序通用的喝多函数,如printf和exit等,下面我们紧接着上一节的知识来实现一个两整数想加的计算并输出计算结果的程序. # libc.s .section .data output: .asciz "The result is %d.

vs2010 win32程序中 sqlserver 2008 express的简单使用 (C++)

由于短学期作业需要在之前程序的服务器中加入数据库,就简单学习了下vs2010中自带的数据库sqlsever2008,学习的过程并不是很顺利,在网上没有找到特别完整的教程,现在课程结束了,特地来写一个,以方便后面的孩纸们,由于本人也是学的半懂不懂的,如果有什么不对的地方还请大家指正! 一.从零开始,建立一个数据库 (1)打开VS2010,工具->连接到数据库,然后在弹出的对话中框选择“Microsoft SQL Server”,单击“继续” (2)在下图所示对话框“服务器名”中输入“自己的计算机名

WIN32 DLL中使用MFC

最近用WIN32 DLL,为了方便要用到MFC的一些库,又不想转工程,就网上找了很多方法,发现没有详细的介绍,有的也行不通,现在成功在WIN32 DLL中使用了MFC,记录一下以防以后用到忘记 一.修改预编译头文件(stdafx.h) 在stdafx.h文件中添加下面代码,包含一些MFC的头文件,这些可以在一个MFC工程中复制过来 #define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // 某些 CString 构造函数将为显式的 #include <afxwin

win32 API中GetSystemMetrics函数

1. SM_ARRANGE: 用于说明系统如何安排最小化窗口,根据显示器的不同系统数据可能有所不同.其包含一个起始位置和方向.关于在程序中怎么使用我还没有见个这样的代码. 起始位置可为下列值之一: ARW_BOTTOMLEFT:开始在左下角的屏幕(默认值). ARW_BOTTOMRIGHT:开始在右下角的屏幕(相当于ARW_STARTRIGHT). ARW_HIDE:在屏幕可见区域隐藏并最小化窗口. ARW_TOPLEFT:从左上角的屏幕上(相当于ARW_STARTTOP). ARW_TOPRI

使用WIN32汇编语言实现一个基本windows窗体的过程分析

一个常规的windows窗体一般都是一些一样的构造.你假设想要更改一些个性化的设置,你能够在这个一般的模板伤添砖加瓦.构造自己比較喜欢的类型.下边就分析一下一般的windows窗体的一般模板. 一. 首先看一下一般的windows窗体都包括什么框架(NO picture you say a J8.....上图上图)例如以下(罗云斌win32汇编书中92页的一张图): 该图简单的描写叙述了一个主要的窗体的框架. 下图是我们分析的第一个窗体的执行演示样例截图: 这个窗体较为简单.可是包括了窗体的基本

WIN32汇编语言之通用对话框的使用

以前学习过自定义的对话框,属性需要自己定义,包括边框,标题,模态与非模态等等,如果创建模态对话框(windows为它内建的消息循环),你不用再去自己写消息循环与注册窗口和显示窗口这几个部分,可以很好的偷懒,这次要介绍的是WINDOWS已经建立好的对话框(已经写好在Comdlg32.dll中),因此当你用到相关的通用对话框的时候,需要在程序的开头写上相关的声明:include comdlg32.inc  与includelib  comdlg32.lib 每当我们使用windows操作系统的时候,

Win32程序中使用 Combo box控件

  SendMessage函数向窗口发送消息 LRESULT SendMessage( HWND hWnd,     // handle to destination window UINT Msg,      // message WPARAM wParam, // first message parameter LPARAM lParam   // second message parameter ); 1 向Combo Box添加数据 HWND hWndComboBox = GetDlgI