Win32汇编系列九,GDI画个寂寞
前言
图片显示,说简单也简单,说难也难,在html中给img指定一个src、在Android中给ImageView指定一个src,还能各种圆角、缩放,但是,这一切在以前学Window的时候是真的困难,想显示一张图片怎么办?,找各种资料,最终只有一个答案,GDI+,GDI+不知道是啥玩意怎么办,在找资料学,最后会发现,显示一个PNG图片,需要十几行左右,还不包括有圆角等。(这里没说C#)。
但今天说的是GDI,GDI+作为GDI的扩展,增强了很多,也复杂了很多,在后续会慢慢介绍,另外本文需要有Window消息机制和GDI的基础,否则可能有点吃力,在后续会慢慢记录此类文章。
主要函数
LoadImage、CreateCompatibleDC、SelectObject、BitBlt。
LoadImage
顾名思义,是用来加载一个位图,也可以加载图标,光标,但是注意,它只能加载位图,也就是BMP,JPG、PNG,没办法。
HANDLE LoadImageA(
HINSTANCE hInst,
LPCSTR name,
UINT type,
int cx,
int cy,
UINT fuLoad
);
-
hInst:包含要加载的图像的DLL或可执行文件的模块句柄。
-
name:要加载的图像
-
type:要加载的图像类型,可以取IMAGE_BITMAP、IMAGE_CURSOR、IMAGE_ICON。
-
cx、cy:图标或光标的宽高。如果为零的话,并且fuLoad参数为LR_DEFAULTSIZE,那么他会使用SM_CXICON或SM_CXCURSOR系统度量值来设置宽高,如果为零,并且没使用LR_DEFAULTSIZE,则该函数使用实际的资源宽高,所以,如果我们不知道图片高宽,需要设置为0,并且fuLoad不能为LR_DEFAULTSIZE。
-
type:这个参数有点多,传LR_LOADFROMFILE就行了。
CreateCompatibleDC
创建一个和当前屏幕DC兼容的内存DC,绘制位图的时候,必须先在内存中建立一个和当前设备环境兼容的DC,然后在利用BitBlt函数将位图从内存复制到屏幕DC上,位图才能显示出来。
参数只有一个,现有设备上下文环境的句柄。
HDC CreateCompatibleDC(
HDC hdc
);
SelectObject
选择一对象到指定的设备上下文环境中,新的对象会替换先前的相同类型的对象。
HGDIOBJ SelectObject(
HDC hdc,
HGDIOBJ h
);
- hdc:设备上下文环境的句柄
- h:被选择的对象的句柄
BitBlt
这个函数好理解,就是从一个地方把图片贴到另一个地方,并且能指定位置和大小。
BOOL BitBlt(
HDC hdc,
int x,
int y,
int cx,
int cy,
HDC hdcSrc,
int x1,
int y1,
DWORD dwRop
);
这里面主要就是hdc、hdcSrc、dwRop参数需要了解,hdc是目标设备上下文的句柄,hdcSrc是源设备上下文的句柄,就是要把hdcSrc的图像复制到hdc中,dwRop是光栅操作的方式,有很多,比如颜色取反,这里就不列举了,选SRCCOPY即可,意思是直接拷贝到hdc中。
其他都是控制位置和大小的参数。
汇编代码
.386
.model flat,stdcall
option casemap:none
include c:\masm32\include\windows.inc
include c:\masm32\include\user32.inc
include c:\masm32\include\msvcrt.inc
include c:\masm32\include\kernel32.inc
include c:\masm32\include\gdi32.inc
includelib c:\masm32\lib\gdi32.lib
includelib c:\masm32\lib\kernel32.lib
includelib c:\masm32\lib\user32.lib
includelib c:\masm32\lib\msvcrt.lib
printf PROTO C : dword,:vararg
WinMain proto :DWORD
.DATA
ClassName db "MyWindowClass",0
AppName db "Win32绘制图片",0
ButtonClassName db "Button",0
ButtonTitle db "绘制",0
HelloGUI db "HelloGUI",0
Message db "完成",0
MessageTitle db "提示",0
OutFmt db "值=%d",0
OutMessage db "第%d次"
.DATA?
hInstance HINSTANCE ?
hWindowHdc HDC ?
hButton HWND ?
hWindow HWND ?
ThreadID DWORD ?
.CONST
ButtonID equ 1
IMAGE_PATH db 'E:\\test\\imgs\\test.bmp' ,0
.CODE
start:
invoke GetModuleHandle, NULL
mov hInstance,eax
invoke WinMain, hInstance
invoke ExitProcess, eax
WinMain proc hInst:HINSTANCE
LOCAL wc:WNDCLASSEX
LOCAL msg:MSG
mov wc.cbSize,SIZEOF WNDCLASSEX
mov wc.style, CS_HREDRAW or CS_VREDRAW
mov wc.lpfnWndProc, OFFSET WndProc
mov wc.cbClsExtra,NULL
mov wc.cbWndExtra,NULL
push hInstance
pop wc.hInstance
mov wc.hbrBackground,COLOR_WINDOW+1
mov wc.lpszMenuName,NULL
mov wc.lpszClassName,OFFSET ClassName
invoke LoadIcon,NULL,IDI_APPLICATION
mov wc.hIcon,eax
mov wc.hIconSm,eax
invoke LoadCursor,NULL,IDC_ARROW
mov wc.hCursor,eax
invoke RegisterClassEx, ADDR wc
invoke CreateWindowEx,NULL,\
ADDR ClassName,\
ADDR AppName,\
WS_OVERLAPPEDWINDOW,\
0,\
0,\
500,\
500,\
NULL,\
NULL,\
hInst,\
NULL
mov hWindow,eax
invoke GetDC,eax
mov hWindowHdc,eax
invoke ShowWindow, hWindow,SW_SHOWDEFAULT
invoke UpdateWindow, hWindow
.WHILE TRUE
invoke GetMessage, ADDR msg,NULL,0,0
.BREAK .IF (!eax)
invoke TranslateMessage, ADDR msg
invoke DispatchMessage, ADDR msg
.ENDW
mov eax,msg.wParam
ret
WinMain endp
WndProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
LOCAL strRect:RECT
LOCAL paint:dword
LOCAL hdcmem:dword
LOCAL hbitmap:dword
LOCAL hdc:dword
.IF uMsg == WM_LBUTTONDOWN
mov strRect.right,100
mov strRect.bottom,100
mov strRect.left,0
mov strRect.top,0
.ELSEIF uMsg ==WM_PAINT
invoke BeginPaint, hWindow, paint
mov hdc,eax
invoke CreateCompatibleDC,hdc
mov hdcmem,eax
invoke LoadImage,hInstance,offset IMAGE_PATH,IMAGE_BITMAP,0,0,LR_LOADFROMFILE
mov hbitmap,eax
invoke SelectObject,hdcmem,hbitmap
invoke BitBlt,hWindowHdc,0,0,500,500,hdcmem,0,0,SRCCOPY
invoke printf,addr OutFmt,hbitmap
invoke EndPaint,hWindow,paint
.ELSE
invoke DefWindowProc,hWnd,uMsg,wParam,lParam
ret
.ENDIF
ret
WndProc endp
end start
这里面需要判断消息是不是WM_PAINT,如果是则开始绘制,WM_PAINT是WIndows中最重要的消息之一,它会在第一次创建窗口、改变窗口大小、把窗口从另一个窗口背后移出、最大化、最小化窗口等等时被触发,在这个消息下通常开始处理绘制的逻辑。
如果我们把他放在如WM_SETFOCUS、按钮单击下绘制,那么当窗体重绘的时候图片就会被"擦除",需要再次触发对应事件进行绘制,而在WM_PAINT消息下绘制正好解决了这些问题。
或者可以颜色取反,dwRop值为NOTSRCCOPY
上一篇: asp.net直接Response输出WML页面示例代码
下一篇: 简单好用的PHP分页类
推荐阅读