Linear Gradient Fill example for MASM
This is an old example I've created for MASM, which was posted in MASM32 forum 2 years ago:
http://www.masm32.com/board/index.php?topic=5944.0
It has a simple approach of double buffering and working with MSIMG32 for the gradient fills.

If you're into drawing in windows (Win32), and you like to program in assembly language; this is example is for you.
Download the source from attachment, or copy the source codes below.
Cheers,
-chris
LinearGradient.asm
.386
.model flat, stdcall
option casemap:none
option proc:private
include windows.inc
include user32.inc
include kernel32.inc
include gdi32.inc
include msimg32.inc
includelib user32.lib
includelib kernel32.lib
includelib gdi32.lib
includelib msimg32.lib
include MsgCrack.inc
; ==========================================================
; Protos
; ==========================================================
WinMain proto :HINSTANCE, :HINSTANCE, :LPSTR, :dword
WndProc proto :HWND, :UINT, :WPARAM, :LPARAM
DrawFancyDivider proto :HDC, :ptr RECT
; ==========================================================
; MessageHandlers Protos
; ==========================================================
WmDestroy proto :HWND
WmCommand proto :HWND, :word, :HWND, :word
WmPaint proto :HWND
option dotname
; ==========================================================
; Local Macros
; ==========================================================
m2m macro mem32A, mem32B
push mem32B
pop mem32A
endm
func macro functionName:req, functionParams:vararg
invoke functionName, functionParams
exitm <eax>
endm
; ==========================================================
; Data
; ==========================================================
.data?
hInstance dd ?
hFont HFONT ?
.data
szClassName db "ChrisVega.WinLion", 0
szWndText db "Win32 Assembly ROCK!", 0
lgFont LOGFONT <-19, 0, 0, 0, 400, 0, 0, 0, 0, 0, 0, 0, 0, "Arial">
szText db "Linear GradientFill sample program by Chris Vega", 0
szTextLen dd $-szText-1
.const
WND_WIDTH = 540
WND_HEIGHT = 180
mnuFileExit = 2001
mnuHelpAbout= 3001
; ==========================================================
; Entry Point
; ==========================================================
.code
start:
invoke WinMain, func(GetModuleHandle, 0), NULL, NULL, SW_SHOW
invoke ExitProcess, 0
; ==========================================================
; WinMain
; ==========================================================
WinMain proc uses edi esi hInst:HINSTANCE, hPrevInst:HINSTANCE, CmdLine:LPSTR, CmdShow:dword
local hwnd:HWND
local msg:MSG
local hMenu:HANDLE
local wc:WNDCLASSEX
; -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
; Register the class
; -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
m2m wc.hInstance, hInst
mov wc.lpszClassName, offset szClassName
mov wc.lpfnWndProc, offset WndProc
mov wc.style, CS_PARENTDC or CS_HREDRAW or CS_VREDRAW
mov wc.cbSize, sizeof WNDCLASSEX
mov wc.hIcon, func(LoadIcon, hInst, 100)
mov wc.hIconSm, eax
mov wc.hCursor, func(LoadCursor, NULL, IDC_ARROW)
mov wc.lpszMenuName, NULL
mov wc.cbClsExtra, 0
mov wc.cbWndExtra, 0
mov wc.hbrBackground, NULL
.if !func(RegisterClassEx, addr wc)
ret
.endif
; -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
; Create the window
; -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
mov edi, func(GetSystemMetrics, SM_CXSCREEN)
shr edi, 1
mov eax, WND_WIDTH
shr eax, 1
sub edi, eax
mov esi, func(GetSystemMetrics, SM_CYSCREEN)
shr esi, 1
mov eax, WND_HEIGHT
shr eax, 1
sub esi, eax
invoke CreateWindowEx,\
WS_EX_APPWINDOW or WS_EX_WINDOWEDGE, \
addr szClassName,\
addr szWndText,\
WS_OVERLAPPEDWINDOW,\
edi,\
esi,\
WND_WIDTH,\
WND_HEIGHT,\
NULL,\
func(LoadMenu, hInst, 1000),\
hInst,\
NULL
mov hwnd, eax
; -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
; Set the window font
; -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
mov hFont, func(CreateFontIndirect, addr lgFont)
; -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
; Make the window visible
; -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
invoke SendMessage, hwnd, WM_SETICON, ICON_BIG or ICON_SMALL, func(LoadIcon, hInst, 1000)
invoke ShowWindow, hwnd, CmdShow
invoke UpdateWindow, hwnd
; -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
; Messageloop (with IsDialogMessage)
; -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
.while TRUE
invoke GetMessage, addr msg, hwnd, 0, 0
.break .if eax!=TRUE
.if !func(IsDialogMessage,hwnd,addr msg)
invoke TranslateMessage, addr msg
invoke DispatchMessage, addr msg
.endif
.endw
; -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
; Exit WinMain
; -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
mov eax, msg.wParam
ret
WinMain endp
; ==========================================================
; Window Procedure
; ==========================================================
WndProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
.handle_msg_begin
.handle_msg WM_DESTROY, WmDestroy
.handle_msg WM_COMMAND, WmCommand
.handle_msg WM_PAINT, WmPaint
.handle_msg_end
invoke DefWindowProc, hWnd, uMsg, wParam, lParam
ret
WndProc endp
; ==========================================================
; DrawFancyDivider
; ==========================================================
DrawFancyDivider proc uses ebx edi hdc:HDC, lpRect:ptr RECT
local pen:HPEN
local pen2:HPEN
mov ebx, lpRect
assume ebx: ptr RECT
invoke CreatePen, PS_SOLID, 1, 00404040h
mov pen, eax
invoke CreatePen, PS_SOLID, 1, 00707070h
mov pen2, eax
invoke SelectObject, hdc, pen
push eax
mov edi, [ebx].top
add edi, 3
invoke MoveToEx, hdc, [ebx].left, edi, NULL
invoke LineTo, hdc, [ebx].right, edi
dec edi
invoke SelectObject, hdc, pen2
invoke MoveToEx, hdc, [ebx].left, edi, NULL
invoke LineTo, hdc, [ebx].right, edi
sub edi, 2
invoke SelectObject, hdc, pen2
invoke MoveToEx, hdc, [ebx].left, edi, NULL
invoke LineTo, hdc, [ebx].right, edi
inc edi
invoke SelectObject, hdc, func(GetStockObject, WHITE_PEN)
invoke MoveToEx, hdc, [ebx].left, edi, NULL
invoke LineTo, hdc, [ebx].right, edi
invoke DeleteObject, pen
invoke DeleteObject, pen2
pop eax
invoke SelectObject, hdc, eax
ret
DrawFancyDivider endp
; ==========================================================
; WmDestroy : Handles WM_DESTROY message
; ==========================================================
WmDestroy proc hWnd:HWND
invoke PostQuitMessage, 0
ret
WmDestroy endp
; ==========================================================
; WmCommand : Handles WM_COMMAND message
; ==========================================================
WmCommand proc hWnd:HWND, id:word, hwndCtl:HWND, codeNotify:word
; ----------------------------------------------
.if id==mnuFileExit
push hWnd
call WmDestroy
; ----------------------------------------------
.elseif id==mnuHelpAbout
invoke MessageBox, hWnd, addr szText, addr szWndText, MB_ICONINFORMATION
; ----------------------------------------------
.endif
ret
WmCommand endp
; ==========================================================
; WmPaint : Handles WM_PAINT message
; ==========================================================
WmPaint proc uses ebx hWnd:HWND
local hdc:HDC
local rect:RECT
local sz:SIZEL
local memDC:HDC
local memBM:HBITMAP
local mesh:GRADIENT_RECT
local vertex[3]:TRIVERTEX
; ---------------------------------------------------------------------
; Get the handle to the device context
; ---------------------------------------------------------------------
mov hdc, func(GetDC, hWnd)
; ---------------------------------------------------------------------
; Get the client rectangle
; ---------------------------------------------------------------------
invoke GetClientRect, hWnd, addr rect
; ---------------------------------------------------------------------
; Create an off-screen device context (double buffering) [1]
; ---------------------------------------------------------------------
mov memDC, func(CreateCompatibleDC, hdc)
mov memBM, func(CreateCompatibleBitmap, hdc, rect.right, rect.bottom)
invoke SelectObject, memDC, memBM
; ---------------------------------------------------------------------
; Populate vertex 1 structure
; ---------------------------------------------------------------------
lea ebx, vertex
assume ebx: ptr TRIVERTEX
m2m [ebx].x, rect.left
m2m [ebx].y, rect.top
mov [ebx].Alpha, 0
mov [ebx].Red, 07d00h
mov [ebx].Green, 0aa00h
mov [ebx].Blue, 0c300h
; ---------------------------------------------------------------------
; Populate vertex 2 structure
; ---------------------------------------------------------------------
add ebx, sizeof TRIVERTEX
m2m [ebx].x, rect.right
m2m [ebx].y, rect.bottom
mov [ebx].Alpha, 0
mov [ebx].Red, 00100h
mov [ebx].Green, 02a00h
mov [ebx].Blue, 04400h
; ---------------------------------------------------------------------
; Set the mesh (gradient rectangle) point
; ---------------------------------------------------------------------
mov mesh.UpperLeft, 0
mov mesh.LowerRight, 1
; ---------------------------------------------------------------------
; Call GradientFill function
; ---------------------------------------------------------------------
invoke GradientFill, memDC, addr vertex, 2, addr mesh, 1, GRADIENT_FILL_RECT_V
; ---------------------------------------------------------------------
; Draw the text, centered to the window
; ---------------------------------------------------------------------
invoke SetBkMode, memDC, TRANSPARENT
invoke SelectObject, memDC, hFont
invoke GetTextExtentPoint32, memDC, addr szText, szTextLen, addr sz
invoke SetTextColor, memDC, 0
mov eax, sz.x
shr eax, 1
mov sz.x, eax
mov eax, sz.y
shr eax, 1
mov sz.y, eax
mov eax, rect.right
sub eax, rect.left
shr eax, 1
sub eax, sz.x
mov edx, rect.bottom
sub edx, rect.top
shr edx, 1
sub edx, sz.y
push eax
push edx
invoke TextOut, memDC, eax, edx, addr szText, szTextLen
invoke SetTextColor, memDC, 00f0f0f0h
pop edx
pop eax
sub edx, 2
sub eax, 2
invoke TextOut, memDC, eax, edx, addr szText, szTextLen
; ---------------------------------------------------------------------
; Draw some fancy divider
; ---------------------------------------------------------------------
invoke DrawFancyDivider, memDC, addr rect
; ---------------------------------------------------------------------
; Flush the result to the window
; ---------------------------------------------------------------------
invoke BitBlt, hdc, 0, 0, rect.right, rect.bottom, memDC, 0, 0, SRCCOPY
; ---------------------------------------------------------------------
; Release all the resources we've used
; ---------------------------------------------------------------------
invoke DeleteDC, memDC
invoke DeleteObject, memBM
; ---------------------------------------------------------------------
; Release the device context
; ---------------------------------------------------------------------
invoke ReleaseDC, hWnd, hdc
; Notes:
; [1] We need to create an off-screen device context for this demo,
; this is because filling a rectangle with GradientFill function
; will take some time to complete, and shows a lot of flickering
; if we let the function use the window's DC.
ret
WmPaint endp
end start