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

 <<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:

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

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

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

这个小兔子的窗口,名字就叫兔兔兔,和小静静的名字一样,哈哈~

阅读更多
个人分类: Win32 ASM
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!
关闭
关闭