说到位图,我们其实很早就接触过,从最早接触计算机,我们应该就知道有图片这个东西,然后再进一步说,图片在电脑上有好几种格式比如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    procLOCAL @hDc,@hDcCircle,@hDcMaskLOCAL @hBmpBack,@hBmpCircle,@hBmpMaskinvoke    GetDC,hWinMainmov       @hDc,eaxinvoke    CreateCompatibleDC,@hDcmov       hDcBack,eaxinvoke    CreateCompatibleDC,@hDcmov       hDcClock,eaxinvoke    CreateCompatibleDC,@hDcmov       @hDcCircle,eaxinvoke    CreateCompatibleDC,@hDcmov       @hDcMask,eaxinvoke    CreateCompatibleBitmap,@hDc,CLOCK_SIZE,CLOCK_SIZEmov       hBmpBack,eaxinvoke    CreateCompatibleBitmap,@hDc,CLOCK_SIZE,CLOCK_SIZEmov       hBmpClock,eaxinvoke    ReleaseDC,hWinMain,@hDcinvoke    LoadBitmap,hInstance,dwNowBackmov       @hBmpBack,eaxinvoke    LoadBitmap,hInstance,dwNowCirclemov       @hBmpCircle,eaxmov       eax,dwNowCircleinc       eax                                                  ;注意此处invoke    LoadBitmap,hInstance,eaxmov       @hBmpMask,eax
如上面代码是_CreateBackGround 子函数的一部分,在标有注释的地方,有一句 代码:
mov       eax,dwNowCircleinc       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 :noneinclude windows.inc
include user32.inc
includelib user32.lib
include kernel32.inc
includelib kernel32.lib
include Gdi32.inc
includelib Gdi32.libCLOCK_SIZE equ150
ICO_MAIN equ 121
IDC_MAIN equ 123
IDC_MOVE equ 122
IDB_BACK1 equ 120
IDB_CIRCLE1 equ118     ;;注意Circle1的ID值必须是加一后等于MASK1的ID值,不然不会成功。
IDB_MASK1 equ 119
IDB_BACK2 equ 117
IDB_CIRCLE2 equ115      ;注意Circle2的ID值必须是加一后等于MASK2的ID值,不然不会成功。
IDB_MASK2 equ 116
ID_TIMER equ 1
IDM_BACK1 equ 100
IDM_BACK2 equ 101
IDM_CIRCLE1 equ102
IDM_CIRCLE2 equ103
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?.constszClassName 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 @dwReturnfild 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 @dwReturnfild 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,@dwY2invoke _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:SYSTEMTIMEpushad
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    procLOCAL @hDc,@hDcCircle,@hDcMaskLOCAL @hBmpBack,@hBmpCircle,@hBmpMaskinvoke    GetDC,hWinMainmov       @hDc,eaxinvoke    CreateCompatibleDC,@hDcmov       hDcBack,eaxinvoke    CreateCompatibleDC,@hDcmov       hDcClock,eaxinvoke    CreateCompatibleDC,@hDcmov       @hDcCircle,eaxinvoke    CreateCompatibleDC,@hDcmov       @hDcMask,eaxinvoke    CreateCompatibleBitmap,@hDc,CLOCK_SIZE,CLOCK_SIZEmov       hBmpBack,eaxinvoke    CreateCompatibleBitmap,@hDc,CLOCK_SIZE,CLOCK_SIZEmov       hBmpClock,eaxinvoke    ReleaseDC,hWinMain,@hDcinvoke    LoadBitmap,hInstance,dwNowBackmov       @hBmpBack,eaxinvoke    LoadBitmap,hInstance,dwNowCirclemov       @hBmpCircle,eaxmov       eax,dwNowCircleinc       eaxinvoke    LoadBitmap,hInstance,eaxmov       @hBmpMask,eaxinvoke    SelectObject,hDcBack,hBmpBackinvoke    SelectObject,hDcClock,hBmpClockinvoke    SelectObject,@hDcCircle,@hBmpCircleinvoke    SelectObject,@hDcMask,@hBmpMaskinvoke    CreatePatternBrush,@hBmpBack                  ;格子背景push      eaxinvoke    SelectObject,hDcBack,eaxinvoke    PatBlt,hDcBack,0,0,CLOCK_SIZE,CLOCK_SIZE,PATCOPYinvoke    DeleteObject,eaxinvoke    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,SRCPAINTinvoke    DeleteDC,@hDcCircleinvoke    DeleteDC,@hDcMaskinvoke    DeleteObject,@hBmpBackinvoke    DeleteObject,@hBmpCircleinvoke    DeleteObject,@hBmpMaskret_CreateBackGround endp_DeleteBackGround procinvoke DeleteDC,hDcBackinvoke DeleteDC,hDcClockinvoke DeleteObject,hBmpBackinvoke DeleteObject,hBmpClockret
_DeleteBackGround endp _Quit procinvoke KillTimer,hWinMain,ID_TIMER
invoke DestroyWindow,hWinMain
invoke PostQuitMessage,NULL
invoke _DeleteBackGround
invoke DestroyMenu,hMenu
ret_Quit endp_Init           procLOCAL   @hBmpBack,@hBmpCircleinvoke  CreatePopupMenumov  hMenu,eaxinvoke  AppendMenu,hMenu,0,IDM_BACK1,offset szMenuBack1invoke  AppendMenu,hMenu,0,IDM_BACK2,offset szMenuBack2invoke  AppendMenu,hMenu,MF_SEPARATOR,0,NULLinvoke  AppendMenu,hMenu,0,IDM_CIRCLE1,offset szMenuCircle1invoke  AppendMenu,hMenu,0,IDM_CIRCLE2,offset szMenuCircle2invoke  AppendMenu,hMenu,MF_SEPARATOR,0,NULLinvoke  AppendMenu,hMenu,0,IDM_EXIT,offset szMenuExitinvoke  CheckMenuRadioItem,hMenu,IDM_CIRCLE1,IDM_CIRCLE2,IDM_CIRCLE1,NULLinvoke  CheckMenuRadioItem,hMenu,IDM_BACK1,IDM_BACK2,IDM_BACK1,NULLinvoke  CreateEllipticRgn,0,0,CLOCK_SIZE+1,CLOCK_SIZE+1push    eaxinvoke  SetWindowRgn,hWinMain,eax,TRUEpop     eaxinvoke  DeleteObject,eaxinvoke  SetWindowPos,hWinMain,HWND_TOPMOST,0,0,0,0,SWP_NOMOVE or SWP_NOSIZEmov     dwNowBack,IDB_BACK1mov     dwNowCircle,IDB_CIRCLE1invoke  _CreateBackGroundinvoke  _CreateClockPicinvoke  SetTimer,hWinMain,ID_TIMER,1000,NULLret_Init endp_ProcWinMain    proc    uses ebx edi esi hWnd,uMsg,wParam,lParamLOCAL   @stPS:PAINTSTRUCTLOCAL   @hDCLOCAL   @stPos:POINTmov     eax,uMsg.if     eax ==  WM_TIMERinvoke  _CreateClockPicinvoke  InvalidateRect,hWnd,NULL,FALSE.elseif eax ==  WM_PAINTinvoke  BeginPaint,hWnd,addr @stPSmov     @hDC,eaxmov     eax,@stPS.rcPaint.rightsub     eax,@stPS.rcPaint.leftmov     ecx,@stPS.rcPaint.bottomsub     ecx,@stPS.rcPaint.topinvoke  BitBlt,@hDC,@stPS.rcPaint.left,@stPS.rcPaint.top,eax,ecx,hDcClock,@stPS.rcPaint.left,\@stPS.rcPaint.top,SRCCOPYinvoke  EndPaint,hWnd,addr @stPS.elseifeax ==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:MSGinvoke GetModuleHandle,NULL
mov hInstance,eax
invoke LoadCursor,hInstance,IDC_MOVE
mov hCursorMove,eax
invoke LoadCursor,hInstance,IDC_MAIN
mov hCursorMain,eaxinvoke 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;如果函数执行失败,那么返回值为FALSESetwindowPos()
功能:
改变一个子窗口,弹出式窗口或顶层窗口的尺寸,位置和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
窗口尺寸和定位的标志。该参数可以是下列值的组合:
SWP_ASYNCWINDOWPOS:如果调用进程不拥有窗口,系统会向拥有窗口的线程发出需求。这就防止调用线程在其他线程处理需求的时候发生死锁。
SWP_DEFERERASE:防止产生WM_SYNCPAINT消息。
SWP_DRAWFRAME:在窗口周围画一个边框(定义在窗口类描述中)。
SWP_FRAMECHANGED:给窗口发送WM_NCCALCSIZE消息,即使窗口尺寸没有改变也会发送该消息。如果未指定这个标志,只有在改变了窗口尺寸时才发送WM_NCCALCSIZE。
SWP_HIDEWINDOW;隐藏窗口。
SWP_NOACTIVATE:不激活窗口。如果未设置标志,则窗口被激活,并被设置到其他最高级窗口或非最高级组的顶部(根据参数hWndlnsertAfter设置)。
SWP_NOCOPYBITS:清除客户区的所有内容。如果未设置该标志,客户区的有效内容被保存并且在窗口尺寸更新和重定位后拷贝回客户区。
SWP_NOMOVE:维持当前位置(忽略X和Y参数)。
SWP_NOOWNERZORDER:不改变z序中的所有者窗口的位置。
SWP_NOREDRAW:不重画改变的内容。如果设置了这个标志,则不发生任何重画动作。适用于客户区和非客户区(包括标题栏和滚动条)和任何由于窗回移动而露出的父窗口的所有部分。如果设置了这个标志,应用程序必须明确地使窗口无效并区重画窗口的任何部分和父窗口需要重画的部分。
SWP_NOREPOSITION:与SWP_NOOWNERZORDER标志相同。
SWP_NOSENDCHANGING:防止窗口接收WM_WINDOWPOSCHANGING消息。
SWP_NOSIZE:维持当前尺寸(忽略cx和Cy参数)。
SWP_NOZORDER:维持当前Z序(忽略hWndlnsertAfter参数)。
SWP_SHOWWINDOW:显示窗口。返回值:
如果函数成功,返回值为非零;如果函数失败,返回值为零CreatepopupMenu()
功能:
创建一个下拉式菜单、子菜单或快捷菜单。此菜单最初是空的,但可用函数InsertMenultem来插入或追加菜单项。也可用函数InsertMenu来插入菜单项,用AppendMenu来追加菜单项。
原型:
HMENU CreatePopupMenu(VOID)
参数:
无
返回值:
如果函数调用成功,返回值是新创建菜单的句柄。如果函数调用失败,返回值是NULL。






WIN32汇编语言中位图的使用相关推荐

  1. 使用MASM04 - Win32汇编语言012

    使用MASM04 让编程改变世界 Change the world by program 调用API函数 习惯工作于DOS汇编的程序员同志都有一个愿望:如果说,能够以功能名称作为子程序名直接调用,他们 ...

  2. Win32汇编语言基础(1)

    汇编语言(assembly language)是一种用于电子计算机.微处理器.微控制器或其他可编程器件的低级语言,亦称为符号语言.在汇编语言中,用助记符(Mnemonics)代替机器指令的操作码,用地 ...

  3. 使用MASM03 - Win32汇编语言011

    使用MASM03 让编程改变世界 Change the world by program 代码段 .code段是代码段,所有的指令都必须写在代码段中,在可执行文件中,代码段是放在_TEXT节区(区块) ...

  4. Win32汇编语言021 - 053

    Win32汇编语言021 - 053 让编程改变世界 Change the world by program 视频下载地址: [buy] 获得所有教学视频.课件.源代码等资源打包 [/buy] [Do ...

  5. ARM汇编语言中的程序结构

    在 ARM ( Thumb )汇编语言程序中,以程序段为单位组织代码.段是相对独立的指令或数据序列,具有特定的名称.段可以分为代码段和数据段,代码段的内容为执行代码,数据段存放代码运行时需要用到的数据 ...

  6. Win32基础知识5 - Win32汇编语言006

    Win32基础知识5 让编程改变世界 Change the world by program Windows的内存安排 这节课我们需要理解三个概念: 每个应用程序都有自己的4 GB的寻址空间,就算这个 ...

  7. 利用c#实现远程注入非托管WIN32程序,并利用嵌入汇编调用非托管WIN32程序中的内部过程...

    c#通过调用windows API函数,可以很轻松的完成非托管WIN32程序的注入.内存读写等操作,以下为c#实现远程注入非托管WIN32程序,并利用嵌入汇编调用非托管WIN32程序中的内部过程的源码 ...

  8. 在Win32程序中创建OpenGL渲染环境

    在Win32程序中创建OpenGL渲染环境 创建opengl渲染环境步骤: 选定像素格式 //WinMain()HDC dc = GetDC(hwnd);PIXELFORMATDESCRIPTOR p ...

  9. 关于汇编语言中的转移指令原理——offset

    offset offset是汇编语言中由编译器进行处理的一种符号. 功能: 取得标号的偏移地址 例题: assume cs:code code segmentstart:mov ax, offset ...

  10. 汇编语言中常用进制数据输出的程序实现

    鲁明珠,赵晓华 (河北省沧州师范专科学校南校区,河北  沧州  061001) [摘   要]在用汇编语言编程时,学生认为将结果数据按不同的数制形式显示出来是一个难点.计算机中的机器数是按二进制形式进 ...

最新文章

  1. SqlDataSource 執行資料篩選
  2. Laravel 5.5 的错误异常处理机制以及应用实例
  3. python使用字典格式化字符串-python实现字符串和字典的转换
  4. 三、新手Jupyter不会用,我十招教你盘她
  5. hdfs路径 linux路径,四、记录1----获取hdfs上FileSystem的方法 记录2:正则匹配路径:linux、hdfs...
  6. P3807-[模板]卢卡斯定理
  7. Windows内存修改初篇
  8. React开发(128):ant design学习指南之input中addonBefore
  9. 【tensorflow】常量张量的初始化
  10. C++ int型与char型辨析
  11. 由ViewStateException: The client disconnected想到的
  12. Django学习--models(模型)
  13. Python学习总结之一 -- 基础篇
  14. SNMP Trap 报文
  15. PMP笔记 第6章 项目进度管理
  16. 软件测试质量报告模板,软件质量报告模板-产品质量度量
  17. 遥感图像场景分类方法总结
  18. 数据库范式:1NF、2NF、3NF、BCNF
  19. 百度飞桨和文心大模型助力,中康科技重构医疗科研大数据治理
  20. ti芯片怎么成为一站式的代理

热门文章

  1. 华为新系统鸿蒙,爆料|疑似华为新MatePad Pro包装盒曝光:搭载鸿蒙OS
  2. net高并发处理技术_高并发业务服务器发生处理的几种状态?
  3. android 3gpp 播放,Android Market:MoboPlayer 最強悍的免費影片播放程式
  4. renpy 如何执行2个action_可执行的网络推广方案如何策划 8个维度 学会了策划方案不求人...
  5. java带参数的构造方法_java练习本(20190603)
  6. 2019如何新建流程图_如何用ppt制作海报和流程图
  7. java -cp 配置文件目录_java – 使用可执行JAR时指定Log4j2配置文件
  8. 密码学基础(二):对称加密
  9. Nginx与tomcat组合的简单使用
  10. ASP .Net Core系统部署到 CentOS7 64 具体方案