Win32汇编教程九

news/2025/3/14 13:47:20
概述

    在前面八篇的 Win32asm 教程中,已经初步讲述了消息框、对话框、菜单、资源、GDI 等内容,基本上已经设计到了 Windows 界面的大部分内容,在继续新的 Windows 其他部分的内容如多线程、文件操作、内存操作之前,我先综合前面的内容并加上一些新内容,写上一篇综合篇。
本篇的例子程序是一个复杂形状的窗口,窗口的形状是根据位图自动计算得到的,这也就是在我编写的小闹钟中使用的技术(大家可以到我的软件发布中下载一个看看),由于以前在网上看到的有关特殊形状窗口的例子最多就是画一个圆形,或者几个方块和椭圆结合的形状,没有一篇文章指出如何画出如“唐老鸭”这样一个造型的窗口。本文使用的算法可以自动根据位图的形状计算窗口形状。
在源程序中,很多代码都是前面教程提到的,主要有以下部分:

  • 首先建立一个标准的窗口。(参考窗口一节)
  • 设置窗口为特殊形状。(见下面的程序分析)
  • 在窗口的 WM_PAINT 消息中更新窗口的图片。(参考图形界面一节)
  • 由于窗口没有标题栏,所以在右击窗口时弹出一个菜单。(参考菜单一节)
  • 菜单中有个“关于本程序”项,里面有超联结文本。(参考窗口子类化一节)

Windows 里有专门的 API 来实现特殊形状的窗口,步骤是首先建立区域(Region),Region 可以合并,这样一来就可以用几个简单的区域合并出一个复杂的区域,建立、合并区域和设置窗口的 API 主要有以下几条:

  • CreateRectRgn(Left,Top,Right,Bottom) - 建立矩型区域
  • CreateEllipticRgn(Left,Top,Right,Bottom) - 建立椭圆区域
  • CreatePolygonRgn(lpPoints,NumberOfPoints,Mode) - 建立多边形区域,这些API返回区域句柄
  • CombineRgn(hDest,hSource1,hSource2,CombineMode) - 合并区域
  • SetWindowRgn(hWnd,hRgn,bRedraw) - 根据区域设置窗口形状

本程序的方法是扫描位图的点,按行设置区域,然后合并到总的区域中。

源程序 - 汇编源文件

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;	是否包括调试代码
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
DEBUG		=	0
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;	Programmed by 罗云彬, bigluo@telekbird.com.cn
;	Website: http://asm.yeah.net
;	LuoYunBin's Win32 ASM page (罗云彬的编程乐园)
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;	版本信息
;	特殊形状窗口的演示程序 Ver 1.0
;	可以根据位图自动设置窗口的形状。
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
.386
.model flat, stdcall
option casemap :none   ; case sensitive
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;	Include 数据
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
include		windows.inc
include		user32.inc
include		kernel32.inc
include		comctl32.inc
include		comdlg32.inc
include		shell32.inc
include		gdi32.inc
includelib	user32.lib
includelib	kernel32.lib
includelib	comctl32.lib
includelib	comdlg32.lib
includelib	shell32.lib
includelib	gdi32.lib
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;	Equ 数据
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;**************	Equ 数据 **********************************
IDI_MAIN	equ		1		;icon
IDC_HANDLE	equ		2		;Cursor
;**************	Equ 数据 **********************************
DLG_ABOUT	equ		1200		;dialog - about
ID_ABOUT_OK	equ		1201
ID_EMAIL	equ		1202
ID_HOMEPAGE	equ		1203
;**************	Equ 数据 **********************************
IDM_MAIN	equ		2000
IDM_ABOUT	equ		2001
IDM_EXIT	equ		2002
;**************	Equ 数据 **********************************
IDB_0		equ 		3000		;bitmap
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;	数据段
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
.data?
hInstance	dd		?
hWinMain	dd		?
hIcon		dd		?
hCursor		dd		?
hMenu		dd		?
hBmpBack	dd		?	;background bitmap
hDcBack		dd		?
;**************	数据段 ************************************
.data
szClassName	db	'ShapeWindow',0
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;	代码段
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
.code
if		DEBUG
include		Debug.asm
endif
;********************************************************************
;	设置窗口形状为BMP图形形状
;	参数:窗口句柄,BMP图形句柄
;	输入BMP图形要求:0,0处颜色为背景色
;********************************************************************
_SetWindowShape	proc	hWnd:DWORD,hBitMap:DWORD
local	@hDC:DWORD,@hBmpDC:DWORD
local	@stPs:PAINTSTRUCT
local	@stRect:RECT
local	@stBmp:BITMAP
local	@dwX:DWORD,@dwY:DWORD,@dwStartX:DWORD
local	@hRgn:DWORD,@hRgnTemp:DWORD
local	@rgbBack:DWORD
invoke	GetObject,hBitMap,sizeof BITMAP,addr @stBmp
invoke	GetWindowRect,hWnd,addr @stRect
invoke	ShowWindow,hWnd,SW_HIDE
invoke	MoveWindow,hWnd,@stRect.left,@stRect.top,/
@stBmp.bmWidth,@stBmp.bmHeight,FALSE
invoke  GetDC,hWnd
mov	@hDC,eax
invoke	CreateCompatibleDC,@hDC
mov	@hBmpDC,eax
invoke	SelectObject,@hBmpDC,hBitMap
;*************** 计算窗口形状 ***************************************
invoke	GetPixel,@hBmpDC,0,0
mov	@rgbBack,eax
invoke	CreateRectRgn,0,0,0,0
mov	@hRgn,eax
mov	@dwY,0
.while	TRUE
mov	@dwX,0
mov	@dwStartX,-1
.while	TRUE
invoke	GetPixel,@hBmpDC,@dwX,@dwY
.if	@dwStartX == -1
.if	eax != @rgbBack
mov	eax,@dwX
mov	@dwStartX,eax
.endif
.else
.if	eax == @rgbBack
mov	ecx,@dwY
inc	ecx
invoke	CreateRectRgn,@dwStartX,@dwY,@dwX,ecx
invoke	CombineRgn,@hRgn,@hRgn,eax,RGN_OR
mov	@dwStartX,-1
.else
mov	eax,@dwX
.if	eax == @stBmp.bmWidth
inc	eax
mov	ecx,@dwY
inc	ecx
invoke	CreateRectRgn,@dwStartX,@dwY,eax,ecx
invoke	CombineRgn,@hRgn,@hRgn,eax,RGN_OR
mov	@dwStartX,-1
.endif
.endif
.endif
inc	@dwX
mov	eax,@dwX
.break	.if eax > @stBmp.bmWidth
.endw
inc	@dwY
mov	eax,@dwY
.break	.if eax > @stBmp.bmHeight
.endw
invoke	SetWindowRgn,hWnd,@hRgn,TRUE
;********************************************************************
invoke	BitBlt,@hDC,0,0,@stBmp.bmWidth,@stBmp.bmHeight,/
@hBmpDC,0,0,SRCCOPY
invoke	DeleteDC,@hBmpDC
invoke	ReleaseDC,hWnd,@hDC
invoke	InvalidateRect,hWnd,NULL,-1
ret
_SetWindowShape	endp
;********************************************************************
;	将窗口移动到屏幕中间
;	参数:窗口句柄
;********************************************************************
_CenterWindow	proc	hWnd:DWORD
local	@stRectDeskTop:RECT,@stRectWin:RECT
local	@dwWidth:DWORD,@dwHeight:DWORD
invoke	GetWindowRect,hWnd,addr @stRectWin
invoke	GetDesktopWindow
mov	ebx,eax
invoke	GetWindowRect,ebx,addr @stRectDeskTop
mov	eax,@stRectWin.bottom
sub	eax,@stRectWin.top
mov	@dwHeight,eax
mov	eax,@stRectWin.right
sub	eax,@stRectWin.left
mov	@dwWidth,eax
mov	ebx,@stRectDeskTop.bottom
sub	ebx,@dwHeight
shr	ebx,1
mov	ecx,@stRectDeskTop.right
sub	ecx,@dwWidth
shr	ecx,1
invoke	MoveWindow,hWnd,ecx,ebx,@dwWidth,@dwHeight,FALSE
ret
_CenterWindow	endp
;********************************************************************
include		About.asm
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;	程序开始
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
start:
call	_WinMain
invoke	ExitProcess,NULL
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;	主窗口程序
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_WinMain	proc
local	@stWcMain:WNDCLASSEX
local	@stMsg:MSG
invoke	InitCommonControls
invoke	GetModuleHandle,NULL
mov	hInstance,eax
invoke	LoadIcon,hInstance,IDI_MAIN
mov	hIcon,eax
invoke	LoadMenu,hInstance,IDM_MAIN
invoke	GetSubMenu,eax,0	;PopUp 菜单要用到子菜单
mov	hMenu,eax
;*************** 注册窗口类 *****************************************
invoke	LoadCursor,0,IDC_ARROW
mov	@stWcMain.hCursor,eax
mov	@stWcMain.cbSize,sizeof WNDCLASSEX
mov	@stWcMain.hIconSm,0
mov	@stWcMain.style,CS_HREDRAW or CS_VREDRAW
mov	@stWcMain.lpfnWndProc,offset WndMainProc
mov	@stWcMain.cbClsExtra,0
mov	@stWcMain.cbWndExtra,0
mov	eax,hInstance
mov	@stWcMain.hInstance,eax
mov	@stWcMain.hIcon,0
mov	@stWcMain.hbrBackground,COLOR_WINDOW + 1
mov	@stWcMain.lpszClassName,offset szClassName
mov	@stWcMain.lpszMenuName,0
invoke	RegisterClassEx,addr @stWcMain
;***************** 建立输出窗口	*****************************************
;	属性:没有标题栏,不显示在任务栏
;********************************************************************
invoke	CreateWindowEx,WS_EX_TOOLWINDOW,/
offset szClassName,NULL,/
WS_POPUP or WS_SYSMENU,/
0,0,1,1,/
NULL,NULL,hInstance,NULL
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
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
WndMainProc	proc	uses ebx edi esi, /
hWnd:DWORD,uMsg:DWORD,wParam:DWORD,lParam:DWORD
local	@stPos:POINT
local	@stPs:PAINTSTRUCT,@hDC:DWORD
mov	eax,uMsg
.if	eax ==	WM_CREATE
mov	eax,hWnd
mov	hWinMain,eax
call	_Init
;********************************************************************
.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,/
hDcBack,@stPs.rcPaint.left,@stPs.rcPaint.top,SRCCOPY
invoke	EndPaint,hWnd,addr @stPs
;********************************************************************
;	由于没有菜单,下面代码用于按下右键时弹出POPUP菜单
;********************************************************************
.elseif eax == WM_RBUTTONDOWN
.if wParam == MK_RBUTTON
invoke	GetCursorPos,addr @stPos
invoke	TrackPopupMenu,hMenu,TPM_LEFTALIGN,@stPos.x,@stPos.y,NULL,hWnd,NULL
.endif
;********************************************************************
;	由于没有标题栏,下面代码用于按下左键时移动窗口
;********************************************************************
.elseif eax == WM_LBUTTONDOWN
invoke	UpdateWindow,hWnd		;即时刷新
invoke	ReleaseCapture
invoke	SendMessage,hWnd,WM_NCLBUTTONDOWN,HTCAPTION,0
;********************************************************************
.elseif	eax ==	WM_COMMAND
.if	lParam == 0
mov	eax,wParam
.if	ax == IDM_EXIT
call	_Quit
.elseif	ax == IDM_ABOUT
invoke	DialogBoxParam,hInstance,DLG_ABOUT,hWnd,offset AboutDialogProc,DLG_ABOUT
.endif
.endif
;********************************************************************
.elseif	eax ==	WM_CLOSE
call	_Quit
;********************************************************************
.else
invoke	DefWindowProc,hWnd,uMsg,wParam,lParam
ret
.endif
;********************************************************************
;	注意:WndProc 处理 Windows 消息后,必须在 Eax 中返回 0
;	但是由 DefWindowProc 处理后的返回值不能改变,否则窗口
;	将无法显示!
;********************************************************************
xor	eax,eax
ret
WndMainProc	endp
;********************************************************************
_Init		proc
local	@hDC
invoke	SendMessage,hWinMain,WM_SETTEXT,0,offset szClassName
invoke	SendMessage,hWinMain,WM_SETICON,ICON_SMALL,hIcon
invoke	LoadBitmap,hInstance,IDB_0	;装入背景图片
mov	hBmpBack,eax
invoke	_SetWindowShape,hWinMain,hBmpBack	;设置窗口形状为背景图片
invoke  GetDC,hWinMain
mov	@hDC,eax
invoke	CreateCompatibleDC,@hDC			;建立背景及数字 DC
mov	hDcBack,eax
invoke	ReleaseDC,hWinMain,@hDC
invoke	SelectObject,hDcBack,hBmpBack
invoke	_CenterWindow,hWinMain
ret
_Init		endp
;********************************************************************
_Quit		proc
local	@stWindow:RECT
invoke	DestroyMenu,hMenu
invoke	DeleteDC,hDcBack
invoke	DeleteObject,hBmpBack
invoke	DestroyWindow,hWinMain
invoke	PostQuitMessage,NULL
ret
_Quit		endp
;********************************************************************
end	start

程序的分析和要点

    创建窗口的时候,窗口风格为 WS_POPUP,所以创建的窗口没有标题栏,这样的窗口适合于设置成特殊形状的窗口

		invoke	CreateWindowEx,WS_EX_TOOLWINDOW,/
offset szClassName,NULL,/
WS_POPUP or WS_SYSMENU,/
0,0,1,1,/
NULL,NULL,hInstance,NULL

但是当窗口没有标题栏后,我们就无法用拖动标题栏的办法来移动窗口,如果让窗口一动不动呆在屏幕中间显然是不行的,这里有一个替代办法,我们可以响应按下鼠标左键的消息,在 WM_LBUTTONDOWN 消息中想窗口发送 WM_NCLBUTTONDOWN (非客户区鼠标按下消息) 位置在 HTCAPTION 来模拟鼠标按在标题栏中来实现移动的功能。

		.elseif eax == WM_LBUTTONDOWN
invoke	UpdateWindow,hWnd		;即时刷新
invoke	ReleaseCapture
invoke	SendMessage,hWnd,WM_NCLBUTTONDOWN,HTCAPTION,0

>> Win32汇编教程之一:Win32汇编的环境和基础>> Win32汇编教程二
>> Win32汇编教程三>> Win32汇编教程四
>> Win32汇编教程五>> Win32汇编教程六
>> Win32汇编教程七>> Win32汇编教程八
>> Win32汇编教程十
>> Win32汇编教程十一>> Win32汇编教程十二
>> Win32汇编教程十三>> Win32ASM经验点滴
>> 汇编语言的艺术(组合语言的艺术)--基本认>> 汇编语言的艺术(组合语言的艺术)--基本认
>> 汇编语言的艺术(组合语言的艺术)--基本认>> 汇编语言的艺术(组合语言的艺术)--准备工
>> 汇编语言的艺术(组合语言的艺术)--观念正>> 如何建立汇编工作环境
也许您还可以去 web开发技术论坛 获得更多您想要的。
<script language="JavaScript" type="text/javascript"> </script>
文章来源:https://blog.csdn.net/hnhbdss/article/details/1412338
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:https://dhexx.cn/news/show-2217956.html

相关文章

代码片段----std::for_each

例程 #include <vector> #include <iostream> #include <algorithm>int add5(int &n) {int re n 5;std::cout << re << " ";return n 5; }class addClass {const int m_a; public:addClass(int _a) : m_a(_a){}void operator()…

高校企业双向赋能,首届飞桨启航菁英计划圆满结束

近年来&#xff0c;随着大数据、人工智能等新兴技术的迅猛发展&#xff0c;以新经济、新产业为背景的“新工科”概念被重磅提出。与此同时&#xff0c;新工科建设也对人才标准提出了更高的要求&#xff0c;产业迫切需要工程实践能力强、创新能力强、具备国际竞争力的高素质复合…

winform 限制启动一个程序

static class Program { /// <summary> /// 应用程序的主入口点。 /// </summary> [STAThread] static void Main() { try { bool ret; System.Threading.Mutex m new Sy…

Win32汇编教程十

概述 Windows 的定时器是一种输入设备&#xff0c;它周期性地在指定的间隔时间通知应用程序。它可以用向指定窗口发送 WM_TIMER 消息或者调用指定的过程来执行用户的程序。定时器的应用主要包括下面一些地方&#xff1a; 时钟程序 - 显然&#xff0c;这是定时器最直接的应用。…

代码片段----cv::FileStorage

Mat的保存和读取 存成图像的Mat失去了精度信息&#xff0c;都是归一到0-255存储的。 存数据的Mat的保存应该使用FileStorage存储成xml. 还有一个用途就是在外部设置程序的参数。对大型工程&#xff08;编译慢&#xff09;的调试特别有用。 #include <opencv2\opencv.hpp&g…

百度智能云与雅量商业智能携手,加速零售行业智能化升级

随着云计算、人工智能、物联网等技术在零售行业的普及&#xff0c;零售行业数字化转型与智能化升级成为趋势。 2021年10月29日&#xff0c;在广州雅量商业智能技术有限公司&#xff08;以下简称“雅量商业智能”&#xff09;“数字中国行数字零售论坛”上&#xff0c;百度智能…

Win32汇编教程十二

Win32汇编教程十二日期&#xff1a;2005-5-7 3:58:12 来源: 编辑&#xff1a; 点击&#xff1a;<script language"JavaScript" type"text/javascript"> </script> <script src"http://www.ithack.net/Click.asp?NewsID0557035…

c# 启动单个程序

static class Program { /// <summary> /// 应用程序的主入口点。 /// </summary> [STAThread] static void Main() { try { bool ret; System.Threading.Mutex m new Sy…

程序片段----新建文件夹

#include <direct.h> #include <string>int main() {std::string folder_path("C:\\test");_mkdir(folder_path.c_str()); // 新建文件夹 成功返回1 return 0; }

百度智能云 × 山东物泽 | 智慧种植,“长出”放心蔬菜

绿色水果&#xff0c;绿色蔬菜&#xff0c;随着健康理念的深入&#xff0c;人们对餐桌上的安全越来越重视。作为全国知名的蔬菜基地寿光&#xff0c;正在通过智慧种植&#xff0c;丰盈餐桌&#xff0c;让每个家庭都吃得安全&#xff0c;吃得放心。 山东物泽生态农业科技发展有…