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
);
  1. hInst:包含要加载的图像的DLL或可执行文件的模块句柄。

  2. name:要加载的图像

  3. type:要加载的图像类型,可以取IMAGE_BITMAP、IMAGE_CURSOR、IMAGE_ICON。

  4. cx、cy:图标或光标的宽高。如果为零的话,并且fuLoad参数为LR_DEFAULTSIZE,那么他会使用SM_CXICON或SM_CXCURSOR系统度量值来设置宽高,如果为零,并且没使用LR_DEFAULTSIZE,则该函数使用实际的资源宽高,所以,如果我们不知道图片高宽,需要设置为0,并且fuLoad不能为LR_DEFAULTSIZE。

  5. type:这个参数有点多,传LR_LOADFROMFILE就行了。

CreateCompatibleDC

创建一个和当前屏幕DC兼容的内存DC,绘制位图的时候,必须先在内存中建立一个和当前设备环境兼容的DC,然后在利用BitBlt函数将位图从内存复制到屏幕DC上,位图才能显示出来。

参数只有一个,现有设备上下文环境的句柄。

HDC CreateCompatibleDC(
  HDC hdc
);

SelectObject

选择一对象到指定的设备上下文环境中,新的对象会替换先前的相同类型的对象。

HGDIOBJ SelectObject(
  HDC     hdc,
  HGDIOBJ h
);
  1. hdc:设备上下文环境的句柄
  2. 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

在这里插入图片描述

©️2020 CSDN 皮肤主题: 数字20 设计师:CSDN官方博客 返回首页