您的位置:首页 > 其它

windows sdk 根据位图,动态创建不规则窗口

2011-10-19 22:35 561 查看
<<windows环境下32位汇编语言程序设计>>里面有个小时钟的程序,提供了原始位图和mask位图,可以选定一种透明色,从而动态绘制出不规则的图案.最后踢了一句,说那个mask位图可以不用资源的,可以动态创建那个mask的位图.他指的方法当然不是用TransparentBlt,而是用GetPixel一个点一个点的去判断.

前几天折腾了一会,结合这个GetPixel的启示,作了一个根据位图,动态创建不规则窗口的例子.



原理很简单:

改变wnd的形状,当然还是需要核心的SetWindowRgn.

创建复杂的窗口形状,需要创建复杂形状的Rgn.这就需要一些规则的Rgn,用CombineRgn()把它们Combine起来

当然,你自己画Path,再PathToRgn也可以。但是这个例子里面还是CombineRgn()各个规则的Rgn



主要步骤

1.准备bmp位图一张,把你不需要的部分染色,MaskColor

这里我用这个小兔兔,设置MaskColor是黑色,黑色的COLORREF竖直应该是0,具体可以在MSDN上查COLORREF怎么表示颜色的



2.把位图读取到dc中

3.创建一个dc大小的OriginRgn

4.循环此位图的各个像素点,察看像素的RGB。这里用到GetPixel()这个API

如果是你要去掉的MaskColor,就CreateRectRgn,设置宽高分别是1像素,并CombineRgn到DelRgn上

5.此时DelRgn是要去掉的所有Rgn 的 CombineRgn后的 Rgn ,OriginRgn是原图片大小的Rgn

这时候再CombineRgn,取两个Rgn不同的Rgn作为结果即可

这里用到 CombineRgn的参数 RGN_XOR,取异或。具体可以查MSDN这个函数怎么用

6.SetWindowRgn,把结果Rgn用上。



主要的汇编代码是这么几句,需要的话可以自行翻译成C或者C++ :

invoke	CreateRectRgn,0,0,100,100
			mov	@hRgnResult,eax	

			mov	@TempRgnX,0
			mov	@TempRgnY,0
			mov	@CurX,0
			mov	@CurY,0
			
			.while	TRUE
				.break .if  @CurY>200
				
				.while	TRUE
				.break	.if	@CurX>200
					
					invoke	GetPixel,hDcDraw,@CurX,@CurY
					mov	ebx,eax
					.if	eax==COLOR_MASK
						;invoke	wsprintf,addr @szBuffer,addr szFormat,@CurX,@CurY
						;invoke	MessageBox,NULL,addr @szBuffer,addr @szBuffer,MB_OK
						mov	eax,@CurX
						inc	eax
						mov	@TempRgnX,eax
						
						mov	eax,@CurY
						inc	eax
						mov	@TempRgnY,eax
						
						invoke	CreateRectRgn,@CurX,@CurY,@TempRgnX,@TempRgnY
						mov	ebx,eax
						.if	ebx==0
							invoke	MessageBox,NULL,addr szRgnFail,addr szRgnFail,MB_OK
						.endif
						
						invoke	CombineRgn,@hRgnResult,@hRgnResult,ebx,RGN_XOR

					.endif	
					
					inc	@CurX
				.endw
				
				mov	@CurX,0
				inc	@CurY
			.endw
			
			invoke	SetWindowRgn,hWinMain,@hRgnResult,TRUE


下面是源代码

gj.rc

#include	<resource.h>
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
#define		IDB_TEST	100
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
IDB_TEST	BITMAP		"mimic2.bmp"
//IDB_TEST	BITMAP		"gj.bmp"



gj.asm

		.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
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
IDB_TEST equ 100
COLOR_MASK equ 0 ; COLORREF 0x00bbggrr
;COLOR_MASK equ 0111111h ; COLORREF 0x00bbggrr
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
.data?
hInstance dd ?
hWinMain dd ?

hBmpTest dd ?
hDcDraw dd ?

.const
szClassName db 'miaoclass',0
szFormat db '(%d,%d)',0
szDebug db 'debug',0

szRgnFail db 'fail!',0

szERRORAPI db 'ERRORAPI',0
szCOMPLEXREGION db 'COMPLEXREGION',0
szSIMPLEREGION db 'SIMPLEREGION',0
szNULLREGION db 'NULLREGION',0

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
.code
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

_ProcWinMain proc uses ebx edi esi hWnd,uMsg,wParam,lParam
LOCAL @hDc
LOCAL @stPs:PAINTSTRUCT
LOCAL @szBuffer[100]:byte

LOCAL @hRgnResult
LOCAL @CurX,@CurY
LOCAL @TempRgnX,@TempRgnY

mov eax,uMsg

.if eax==WM_CREATE
push hWnd
pop hWinMain

; load bitmap
invoke LoadBitmap,hInstance,IDB_TEST
mov hBmpTest,eax

; create buffer dc
invoke GetDC,hWnd
mov @hDc,eax
invoke CreateCompatibleDC,@hDc
mov hDcDraw,eax
invoke ReleaseDC,hWnd,@hDc

; draw sth. on bufferdc
invoke SelectObject,hDcDraw,hBmpTest

;invoke CreateEllipticRgn,0,0,100,100
;mov @hRgnResult,eax
;invoke CreateEllipticRgn,150,150,200,200
;invoke CombineRgn,@hRgnResult,@hRgnResult,eax,RGN_OR
;invoke SetWindowRgn,hWnd,@hRgnResult,FALSE


invoke CreateRectRgn,0,0,100,100 mov @hRgnResult,eax mov @TempRgnX,0 mov @TempRgnY,0 mov @CurX,0 mov @CurY,0 .while TRUE .break .if @CurY>200 .while TRUE .break .if @CurX>200 invoke GetPixel,hDcDraw,@CurX,@CurY mov ebx,eax .if eax==COLOR_MASK ;invoke wsprintf,addr @szBuffer,addr szFormat,@CurX,@CurY ;invoke MessageBox,NULL,addr @szBuffer,addr @szBuffer,MB_OK mov eax,@CurX inc eax mov @TempRgnX,eax mov eax,@CurY inc eax mov @TempRgnY,eax invoke CreateRectRgn,@CurX,@CurY,@TempRgnX,@TempRgnY mov ebx,eax .if ebx==0 invoke MessageBox,NULL,addr szRgnFail,addr szRgnFail,MB_OK .endif invoke CombineRgn,@hRgnResult,@hRgnResult,ebx,RGN_XOR .endif inc @CurX .endw mov @CurX,0 inc @CurY .endw invoke SetWindowRgn,hWinMain,@hRgnResult,TRUE

.elseif eax==WM_LBUTTONDOWN
invoke UpdateWindow,hWnd
invoke SendMessage,hWnd,WM_NCLBUTTONDOWN,HTCAPTION,0

;invoke ReleaseCapture
;invoke SetCursor,hCursorMain

.elseif eax==WM_CLOSE
invoke DeleteObject,hDcDraw
invoke DeleteObject,hBmpTest

invoke DestroyWindow,hWnd
invoke PostQuitMessage,NULL


.elseif eax==WM_PAINT
invoke BeginPaint,hWnd,addr @stPs
mov @hDc,eax
invoke BitBlt,@hDc,0,0,300,300,hDcDraw,0,0,SRCCOPY
invoke EndPaint,hWnd,addr @stPs
.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 RtlZeroMemory,addr @stWndClass,sizeof @stWndClass
invoke LoadCursor,NULL,IDC_ARROW
mov @stWndClass.hCursor,eax
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,WS_EX_CLIENTEDGE,offset szClassName,offset szClassName,\
WS_POPUP or WS_SYSMENU,\
;WS_OVERLAPPEDWINDOW,\
100,100,100,100,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



效果图

有点花哨,中间那个小兔兔就是程序的窗口了~





顺便说一下 上面的代码里,

WM_LBUTTONDOWN的部分,是按下鼠标左键,可以拖动窗口的功能。

采用的是转发 WM_NCLBUTTONDOWN+HTCAPTION的原理,就是欺骗WINDOWS,说我点的是标题栏。



总结一下这个例子,

本身就是API的堆积,思想很简单.

但是实现的时候有个地方卡勒好久,就是用汇编计算坐标的时候.

汇编里面的变量不像C语言这种高级语言,能够按照想像中的工作.

比如坐标值+1,最后却出现了一个非常非常大的数值.

而我这里又没法Debug win32 asm程序,这个错误调试了两个小时才发现..

汇编语言处处是坑阿~~!



在网上搜索到一篇文章,VC 6.0 倒是可以 单步调试 win32汇编,

可惜又没有语法高亮,又没有语法提示,反而到不如RadAsm

可RadAsm的Debug工具竟然是OllyDbg!!这东西.....暂时还不会用,还得学习啊....

比 VC 里的Debug工具可难用多了.



真希望能够找到一个好的 win32 asm开发环境.



不过我觉得以后还是很有必要学习学习用OllyDbg来调试程序的,

如果现在就用OllyDbg调试自己的程序,将来用它来破解软件,肯定是轻车熟路了!

恩,有空的时候还得加把劲学习啊!



OK, OVER .



PS:

本来打算在等小静静的时候,学习点新的东西的。

但是实在是太困了,没精神,学习不下去呀。。

小静静几点下班亚,困死我了………………

这个小兔子的窗口,名字就叫兔兔兔,和小静静的名字一样,哈哈~
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: