flat assembler
Message board for the users of flat assembler.

Index > Tutorials and Examples > GradientFill example.

Goto page 1, 2, 3  Next
Author
Thread Post new topic Reply to topic
MHajduk



Joined: 30 Mar 2006
Posts: 6115
Location: Poland
MHajduk 28 Mar 2013, 23:46
I'd like to present here a simple example of how to use Windows 'GradientFill' function to fill the application window background with gradient. The program is as simple as it is possible and may be treated as a ready-to-use windows application template, anyway to avoid possible flickering while resize there is added some kind of necessary buffering.

Image

http://www.youtube.com/watch?v=2P-y8T34DVw

I've decided to post this example here because the gradient fill examples posted on this forum represent mainly low-level approach with custom drawing procedures (uart777 graphic examples, 0.1 (written with C) and ATV examples).

There was literally one example by Vasilev Vjacheslav using the 'GradientFill' function but the clue is hidden among too many things to be useful as a simple example for everybody (especially beginners).



Here you have a source code of my program:
Code:
;
; A simple program written with FASM that shows how to fill an application window
; background with color gradient using the 'GradientFill' function.
;
; Program uses buffering to avoid possible flickering during the application window
; resize.
;
; (C) Mikolaj Hajduk, 28.03 - 06.04.2013.
;
format PE GUI 4.0

entry start


; Include a header file containing necessary macros.
;
include 'win32wx.inc'

; Use UTF-8 encoding if you want to have your strings displayed always the same
; way despite of local settings of the user system and if your application has to
; be multilingual.
;
include 'ENCODING\utf8.inc'

; A definition of the constant describing the program version (encoded date of
; the last changes).
;
PROG_VERSION equ '2013.04.06.0'

; Symbolic constants used as equivalents of the button dimensions.
;
BTN_WIDTH       = 150
BTN_HEIGHT      = 40

; A definition of the structure specifying indexes of two vertices in the array
; of TRIVERTEX structures used by GradientFill function. Chosen vertices determine
; the upper-left and lower-right boundaries of the rectangle filled with gradient.
;
struct GRADIENT_RECT
        UpperLeft       dd ?
        LowerRight      dd ?
ends

; Constants specifying possible gradient fill modes.
;
GRADIENT_FILL_RECT_H            = 0x0   ; Horizontal gradient.

GRADIENT_FILL_RECT_V            = 0x1   ; Vertical gradient.

; A constant used to define private messages within the scope of the application.
;
WM_APP          = 0x8000

; A code of the application specific message used to change gradient colors
; from default to custom ones.
;
WM_SETGRADIENT  = WM_APP


; The data section.
;
section '.data' data readable writeable

        HwndMain        dd 0    ; The handle of the main application window.

        HwndBis         dd 0    ; The handle of the additional resizable application
                                ; window.

        hFont           dd 0    ; The handle of the font used to display strings
                                ; inside window controls.

        ; An arbitrarily chosen class name of the created window.
        ;
        ClassName       du 'GradientFillExample', 0

        ; A string displayed in the application window title bar.
        ;
        WindowCaption   du 'Gradient fill example v.', PROG_VERSION, 0

        ; An instance of the WNDCLASSEX structure containing information about
        ; the created window class.
        ;
        wc              WNDCLASSEX      sizeof.WNDCLASSEX, 0, WindowProc, 0,\
                                        \
                                        8,\     ; The number of extra bytes allocated
                                        \       ; following every class instance.
                                        \       ; Here we need two double words for
                                        \       ; a button handle (first dword) and
                                        \       ; a 32-bit pointer to the array of the
                                        \       ; TRIVERTEX structure instances defining
                                        \       ; colors of actual gradient.
                                        \
                                        NULL, NULL, NULL, NULL, NULL,\
                                        \
                                        ClassName, NULL

        ; An instance of the MSG structure used to store information about
        ; messages from the thread message queue.
        ;
        msg             MSG

        ; The name of the used font. 'Tahoma' is the proper choice for applications
        ; that display strings denoted in the scripts other than Latin (supports
        ; most Unicode chars).
        ;
        FontName        du 'Tahoma', 0

        ; A constant used in INITCOMMONCONTROLSEX as a flag indicating that
        ; all standard common control classes have to be loaded from the DLL.
        ;
        ICC_STANDARD_CLASSES = 0x4000

        ; An instance of the structure carrying information used to load common
        ; control classes.
        ;
        icex            INITCOMMONCONTROLSEX    sizeof.INITCOMMONCONTROLSEX, ICC_STANDARD_CLASSES

        align 4

        ; A custom array of instances of the TRIVERTEX structure containing information
        ; about colors associated with upper-left and lower-right corners of the window
        ; application client area.
        ;
        ;                                       Upper-left
        ;                                       x       y       R       G       B       Alpha
        ;                                       ---------------------------------------------
        CustomVertices          TRIVERTEX       0,      0,      07D00h, 0AA00h, 0C300h, 0
                                TRIVERTEX       0,      0,      07D00h, 0FF00h, 04400h, 0

        ; Default array of instances of the TRIVERTEX structure containing information
        ; about colors associated with upper-left and lower-right corners of the window
        ; application client area.
        ;
        ;                                       Upper-left
        ;                                       x       y       R       G       B       Alpha
        ;                                       ---------------------------------------------
        DefaultVertices         TRIVERTEX       0,      0,      07D00h, 0AA00h, 0C300h, 0
                                TRIVERTEX       0,      0,      0FF00h, 02A00h, 04400h, 0

        ; An instance of the 'GRADIENT_RECT' structure determining indexes
        ; of the array of 'TRIVERTEX' structures used by 'GradientFill' function
        ; to fill an area with gradient.
        ;
        Mesh                    GRADIENT_RECT   0, 1


; The code section.
;
section '.code' code readable executable

        start:
                ; Ensure that the common control DLL (Comctl32.dll) is loaded
                ; and register chosen common control classes.
                ;
                invoke  InitCommonControlsEx, icex

                stdcall ErrorRoutine, exit

                ; Retrieve a handle of the application file.
                ;
                invoke  GetModuleHandle, 0

                stdcall ErrorRoutine, exit

                mov     [wc.hInstance], eax

                ; As an application icon use one of the predefined icons.
                ;
                invoke  LoadIcon, 0, IDI_APPLICATION

                stdcall ErrorRoutine, exit

                mov     [wc.hIcon], eax

                ; A cursor associated with the application is a standard, arrow
                ; shaped one.
                ;
                invoke  LoadCursor, 0, IDC_ARROW

                stdcall ErrorRoutine, exit

                mov     [wc.hCursor], eax

                ; Registering the application window class in the system.
                ;
                invoke  RegisterClassEx, wc

                stdcall ErrorRoutine16, exit

                ; Create the main application window.
                ;
                invoke  CreateWindowEx, 0, ClassName, WindowCaption, WS_VISIBLE + WS_OVERLAPPEDWINDOW +\
                                \
                                WS_CLIPCHILDREN,\       ; Exclude child windows from redrawing when
                                \                       ; the drawing occurs within the parent, i.e.
                                \                       ; main application window area.
                                \
                                128, 128, 350, 192, NULL, NULL, [wc.hInstance], NULL

                stdcall ErrorRoutine, exit

                mov     [HwndMain], eax

                ; Create an additional resizable application window.
                ;
                invoke  CreateWindowEx, 0, ClassName, WindowCaption, WS_VISIBLE + WS_SIZEBOX +\
                                \
                                WS_CLIPCHILDREN,\       ; Exclude child windows from redrawing when
                                \                       ; the drawing occurs within the parent, i.e.
                                \                       ; main application window area.
                                \
                                300, 300, 350, 192, NULL, NULL, [wc.hInstance], NULL

                stdcall ErrorRoutine, exit

                mov     [HwndBis], eax

                ; Create a font that will be used to display all strings inside
                ; the application window controls.
                ;
                invoke  CreateFont, 16, 0, 0, 0, 0, FALSE, FALSE, FALSE,\
                                DEFAULT_CHARSET, OUT_RASTER_PRECIS, CLIP_DEFAULT_PRECIS,\
                                DEFAULT_QUALITY, FIXED_PITCH + FF_DONTCARE, FontName

                stdcall ErrorRoutine, cleanup

                mov     [hFont], eax

                ; Set the created font to the main and additional application windows.
                ;
                invoke  SendMessage, [HwndMain], WM_SETFONT, eax, TRUE

                invoke  SendMessage, [HwndBis], WM_SETFONT, [hFont], TRUE

                ; Change the default gradient to the custom one in the additional
                ; application window.
                ;
                invoke  SendMessage, [HwndMain], WM_SETGRADIENT, CustomVertices, 0

        ; A loop where all messages referring to the application window have been
        ; processed.
        ;
        msg_loop:
                ; Retrieve a message from the application message queue.
                ;
                invoke  GetMessage, msg, NULL, 0, 0

                ; Exit when the 'WM_QUIT' message has been retrieved.
                ;
                test    eax, eax
                jz      cleanup

                ; Display a proper error message when something has gone wrong
                ; (eax = -1).
                ;
                inc     eax

                stdcall ErrorRoutine, cleanup

                ; Translate virtual-key strokes into character messages.
                ;
                invoke  TranslateMessage, msg

                ; Dispatch the retrieved message to the window procedure.
                ;
                invoke  DispatchMessage, msg
                jmp     msg_loop

        ; Release all handles and allocated resources before exit.
        ;
        cleanup:
                ; Delete the font used to display strings in the application
                ; window controls.
                ;
                cmp     [hFont], 0
                je      exit

                invoke  DeleteObject, [hFont]

        ; Quit the application.
        ;
        exit:
                invoke  ExitProcess, [msg.wParam]

        ; The error handling routine that organizes the program flow when any of
        ; API functions returns zero value.
        ;
        ErrorRoutine16:
                ; Zeroize bits of the eax register from the 16th to the 31st one.
                ; Done to assure that the eax register won't contain any "garbage"
                ; after calling API functions returning 16-bit result.
                ;
                and     eax, 0xFFFF

        ErrorRoutine:
                ; Check value stored in the eax register. If it's nonzero then
                ; return to the address following the place the error procedure
                ; has been called.
                ;
                test    eax, eax
                jz      @f

                retn    4

                ; Check value of the last error that has occurred.
                ;
                @@:
                invoke  GetLastError
                test    eax, eax
                jnz     @f

                ; If there was no error, i.e. the 'GetLastError' function returned
                ; 'ERROR_SUCCESS', we return to the place when the 'ErrorRoutine'
                ; procedure was called and remove the 'ReturnTo' address stored on
                ; the stack before the procedure call.
                ;
                retn    4

                @@:
                ; If there was an error, we display a message box with a human readable
                ; description of the error, remove the address of the procedure caller
                ; and return to the 'ReturnTo' address.
                ;
                stdcall ShowLastError, NULL, eax

                add     esp, 4
                retn

        ; The main application window procedure. Here we specify how to react
        ; on the events occurring inside the window.
        ;
        proc    WindowProc, hwnd, wmsg, wparam, lparam

                locals
                        .Button         dd 0    ; The handle of the button.

                        .hVertices      dd 0    ; A 32-bit pointer to the array of the TRIVERTEX
                                                ; structure instances used to define gradient
                                                ; colors.

                        .hDC            dd 0    ; The handle of the application window DC.

                        .hMemDC         dd 0    ; The handle of the additional DC (buffer).

                        .hMemBM         dd 0    ; The handle of the bitmap used for the
                                                ; window redraw operations.

                        .Rect           RECT    ; An instance of the RECT structure used
                                                ; to store the coordinates of the upper-left
                                                ; and the lower-right corners of the window
                                                ; client area.
                endl

                push    ebx

                ; Depending on the message type perform proper actions.
                ;
                cmp     [wmsg], WM_CREATE
                je      .wmcreate

                ; Retrieve the handle of the button from the window extra memory and store
                ; it in the local variable '.Button'.
                ;
                invoke  GetWindowLong, [hwnd], 0

                stdcall ErrorRoutine, .wmdestroy

                mov     [.Button], eax

                ; Retrieve the pointer to the array of the TRIVERTEX structure instances
                ; and store it in the local variable '.hVertices'.
                ;
                invoke  GetWindowLong, [hwnd], 4

                stdcall ErrorRoutine, .wmdestroy

                mov     [.hVertices], eax

                cmp     [wmsg], WM_SIZE
                je      .wmsize

                cmp     [wmsg], WM_PAINT
                je      .wmpaint

                cmp     [wmsg], WM_SETFONT
                je      .wmsetfont

                cmp     [wmsg], WM_SETGRADIENT
                je      .wmsetgradient

                cmp     [wmsg], WM_DESTROY
                je      .wmdestroy

                ; Ensure that all messages not processed by the application
                ; window procedure will be processed by default window procedure.
                ;
                .defwndproc:
                        invoke  DefWindowProc, [hwnd], [wmsg], [wparam], [lparam]
                        jmp     .finish


                ; Actions performed when the application window has been created.
                ;
                .wmcreate:
                        ; Create an exemplary button.
                        ;
                        invoke  CreateWindowEx, 0, 'BUTTON', 'Button',\
                                        WS_VISIBLE + WS_CHILD,\
                                        0, 0, 0, 0, [hwnd], 0, [wc.hInstance], NULL

                        stdcall ErrorRoutine, .wmdestroy

                        mov     [.Button], eax

                        ; Store the handles created button handle and pointer to the array
                        ; of the TRIVERTEX structure instances in the reserved window extra
                        ; memory. It's necessary because these values must be available
                        ; during the next call of the 'WindowProc' procedure.
                        ;
                        invoke  SetLastError, 0
                        invoke  SetWindowLong, [hwnd], 0, [.Button]

                        stdcall ErrorRoutine, .wmdestroy

                        invoke  SetLastError, 0
                        invoke  SetWindowLong, [hwnd], 4, DefaultVertices

                        stdcall ErrorRoutine, .wmdestroy

                        ; Window procedure should return 0 when processes the 'WM_CREATE'
                        ; message.
                        ;
                        jmp .return0

                ; Actions performed when the application window has changed its sizes.
                ;
                .wmsize:
                        ; Retrieve the coordinates of the application window client area.
                        ; The result of the procedure 'GetClientRect' is stored in the
                        ; instance of the RECT structure. The coordinates of the upper-left
                        ; corner of the client area rectangle are always equal to (0, 0),
                        ; so the most important are coordinates of the lower-right corner
                        ; as a containing the whole information.
                        ;
                        lea     eax, [.Rect]
                        invoke  GetClientRect, [hwnd], eax

                        stdcall ErrorRoutine, .finish

                        ; Put the width of the client area to the eax register, subtract
                        ; the width of the button and divide the result by 2 to obtain
                        ; the new x coordinate of the upper-left corner of the button.
                        ;
                        mov     eax, [.Rect.right]
                        sub     eax, BTN_WIDTH
                        shr     eax, 1

                        ; Put the height of the client area to the ebx register, subtract
                        ; the height of the button and divide the result by 2 to obtain
                        ; the new y coordinate of the upper-left corner of the button.
                        ;
                        mov     ebx, [.Rect.bottom]
                        sub     ebx, BTN_HEIGHT
                        shr     ebx, 1

                        ; Move the button to the calculated position.
                        ;
                        invoke  MoveWindow, [.Button], eax, ebx, BTN_WIDTH, BTN_HEIGHT, TRUE

                        stdcall ErrorRoutine, .finish

                        ; Window procedure should return 0 when processes the 'WM_SIZE'
                        ; message.
                        ;
                        jmp     .return0

                ; Actions performed when a portion of the application window needs to be redrawn.
                ;
                .wmpaint:
                        ; Retrieve a handle to a device context of the client area of the
                        ; application window.
                        ;
                        invoke  GetDC, [hwnd]

                        stdcall ErrorRoutine, .finish

                        mov     [.hDC], eax

                        ; Retrieve the coordinates of the application window client area.
                        ;
                        lea     eax, [.Rect]
                        invoke  GetClientRect, [hwnd], eax

                        stdcall ErrorRoutine, .wmpaintcleanup

                        ;
                        ; Sequence of actions performed in order to buffer all redraw operations.
                        ;

                        ; Create an additional, memory device context compatible with DC of the
                        ; client area of our application window.
                        ;
                        invoke  CreateCompatibleDC, [.hDC]

                        stdcall ErrorRoutine, .wmpaintcleanup

                        mov     [.hMemDC], eax

                        ; Create a bitmap used to hold the result of the window redraw, assigned
                        ; to the DC of the application window.
                        ;
                        invoke  CreateCompatibleBitmap, [.hDC], [.Rect.right], [.Rect.bottom]

                        stdcall ErrorRoutine, .wmpaintcleanup

                        mov     [.hMemBM], eax

                        ; Change the default bitmap used in additional DC by the one created above.
                        ;
                        invoke  SelectObject, [.hMemDC], [.hMemBM]

                        stdcall ErrorRoutine, .wmpaintcleanup

                        ; Actualization of the coordinates of the structure pointed by '.hVertices'
                        ; with actual coordinates of the lower-right corner of the client area (fields
                        ; corresponding to the upper-left corner don't need to be actualized as they
                        ; are always equal to 0).
                        ;
                        mov     ebx, [.hVertices]
                        add     ebx, sizeof.TRIVERTEX   ; We refer to the second instance of the
                                                        ; TRIVERTEX structure in the array pointed
                                                        ; by '.hVertices'.

                        mov     eax, [.Rect.right]
                        mov     [ebx], eax              ; Lower-right x coordinate.

                        mov     eax, [.Rect.bottom]
                        mov     [ebx + 4], eax          ; Lower-right y coordinate.

                        ; Fill the application window background with gradient.
                        ;
                        invoke  GradientFill, [.hMemDC],\               ; The handle of the additional device
                                                \                       ; context where we perform all drawing
                                                \                       ; operations.
                                                \
                                                [.hVertices],\          ; The pointer to the array of 'TRIVERTEX'
                                                \                       ; structures that define vertices of the
                                                \                       ; area filled with gradient.
                                                \
                                                2,\                     ; Number of vertices in the array mentioned
                                                \                       ; above.
                                                \
                                                Mesh,\          ; A pointer to an array of the 'GRADIENT_RECTANGLE'
                                                \                       ; structures (specify the way we interpret the
                                                \                       ; vertices contained in the 'TRIVERTEX' structures
                                                \                       ; array).
                                                \
                                                1,\                     ; The number of rectangles in the array
                                                \                       ; mentioned above.
                                                \
                                                GRADIENT_FILL_RECT_V    ; The gradient fill mode (here: vertical).

                        stdcall ErrorRoutine, .wmpaintcleanup

                        ; Copy data of the newly drawn background from the source device context
                        ; (buffer) to the destination device context (DC associated with the client
                        ; area of our application window).
                        ;
                        invoke  BitBlt, [.hDC],\                ; The handle of the destination DC.
                                        \
                                        0, 0,\                  ; The coordinates of the upper-left corner
                                        \                       ; of the destination DC.
                                        \
                                        [.Rect.right],\         ; The width and height of the destination
                                        [.Rect.bottom],\        ; device context.
                                        \
                                        [.hMemDC],\             ; The handle of the source DC (memory buffer).
                                        \
                                        0, 0,\                  ; The coordinates of the upper-left corner
                                        \                       ; of the source DC.
                                        \
                                        SRCCOPY                 ; A raster-operation code (ordinary copy).

                        stdcall ErrorRoutine, .wmpaintcleanup

                        ; Release all handles and resources used during painting.
                        ;
                        .wmpaintcleanup:
                                ; Delete the additional unneeded device context.
                                ;
                                cmp     [.hMemDC], 0
                                je      .hMemBMdelete

                                invoke  DeleteDC, [.hMemDC]

                                ; Release resources occupied by the bitmap associated with the
                                ; application DC.
                                ;
                                .hMemBMdelete:
                                        cmp     [.hMemBM], 0
                                        je      .hDCrelease

                                        invoke  DeleteObject, [.hMemBM]

                                ; Release the application window device context retrieved by the
                                ; 'GetDC' function call.
                                ;
                                .hDCrelease:
                                        cmp     [.hDC], 0
                                        je      .wmdestroy

                                        invoke  ReleaseDC, [hwnd], [.hDC]

                                xor     eax, eax

                                jmp     .defwndproc

                ; Actions performed when the window procedure receives the 'WM_SETFONT'
                ; message. Here we forward the 'WM_SETFONT' message to all controls
                ; located inside the window.
                ;
                .wmsetfont:
                        ; Set the new font to the button instead the current one.
                        ;
                        invoke  SendMessage, [.Button], WM_SETFONT, [wparam], TRUE

                        jmp     .finish

                ; Actions performed when the window procedure receives the custom
                ; 'WM_SETGRADIENT' message. We change the pointer to the array of
                ; TRIVERTEX structure instances to the new one passed through 'wparam'
                ; parameter of the window procedure.
                ;
                .wmsetgradient:
                        invoke  SetLastError, 0
                        invoke  SetWindowLong, [hwnd], 4, [wparam]

                        stdcall ErrorRoutine, .finish

                        jmp     .finish

                ; Operations performed when the application window is to be destroyed.
                ; This is a regular cleanup after receiving the 'WM_DESTROY' message: here
                ; we delete objects and resources allocated during the application window
                ; creation. We don't need to destroy all controls (child windows) manually
                ; because it will be done automatically.
                ;
                .wmdestroy:
                        ; Post the 'WM_QUIT' message to the application message queue.
                        ;
                        invoke  PostQuitMessage, 0

                .return0:
                        xor     eax, eax

                .finish:
                        pop     ebx
                        ret
        endp

        ; A simple procedure that displays a message box containing a human readable
        ; description of the last error.
        ;
        proc    ShowLastError, hwnd, LastErr

                locals
                        Buffer dd ?
                endl

                lea     eax, [Buffer]
                invoke  FormatMessage, FORMAT_MESSAGE_ALLOCATE_BUFFER + FORMAT_MESSAGE_FROM_SYSTEM, 0, [LastErr],\
                                LANG_NEUTRAL, eax, 0, 0

                invoke  MessageBox, [hwnd], [Buffer], NULL, MB_ICONERROR + MB_OK
                invoke  LocalFree, [Buffer]

                ret
        endp


; The import section.
;
section ".idata" import data readable writeable

library kernel32,               "KERNEL32.DLL",\
        user32,                 "USER32.DLL",\
        gdi32,                  "GDI32.DLL",\
        comctl32,               "COMCTL32.DLL",\
        msimg32,                "MSIMG32.DLL"

import  kernel32,\
        ExitProcess,            "ExitProcess",\
        FormatMessage,          "FormatMessageW",\
        GetLastError,           "GetLastError",\
        GetModuleHandle,        "GetModuleHandleW",\
        LocalFree,              "LocalFree",\
        SetLastError,           "SetLastError"

import  user32,\
        CreateWindowEx,         "CreateWindowExW",\
        DefWindowProc,          "DefWindowProcW",\
        DispatchMessage,        "DispatchMessageW",\
        GetClientRect,          "GetClientRect",\
        GetDC,                  "GetDC",\
        GetMessage,             "GetMessageW",\
        GetWindowLong,          "GetWindowLongW",\
        LoadCursor,             "LoadCursorW",\
        LoadIcon,               "LoadIconW",\
        MessageBox,             "MessageBoxW",\
        MoveWindow,             "MoveWindow",\
        PostQuitMessage,        "PostQuitMessage",\
        RegisterClassEx,        "RegisterClassExW",\
        ReleaseDC,              "ReleaseDC",\
        SendMessage,            "SendMessageW",\
        SetWindowLong,          "SetWindowLongW",\
        TranslateMessage,       "TranslateMessage"

import  gdi32,\
        BitBlt,                 "BitBlt",\
        CreateCompatibleBitmap, "CreateCompatibleBitmap",\
        CreateCompatibleDC,     "CreateCompatibleDC",\
        CreateFont,             "CreateFontW",\
        DeleteDC,               "DeleteDC",\
        DeleteObject,           "DeleteObject",\
        SelectObject,           "SelectObject"

import  comctl32,\
        InitCommonControlsEx,   "InitCommonControlsEx"

import  msimg32,\
        GradientFill,           "GradientFill"


; The section of the program resources. Here we specify information about the
; application (description, author, version) and the application manifest
; informing Windows which version of the common controls program should use
; giving it a modern visual style instead of the classical Win9x "boxy" style.
;
section '.rsrc' resource data readable

        RT_MANIFEST     = 24
        ID_MANIFEST     = 1

        directory       RT_VERSION, versions,\
                        RT_MANIFEST, manifest

        resource        versions,\
                        1, LANG_NEUTRAL, version

        resource        manifest,\
                        ID_MANIFEST, LANG_NEUTRAL, man

        versioninfo     version, VOS__WINDOWS32, VFT_APP, VFT2_UNKNOWN, LANG_ENGLISH + SUBLANG_DEFAULT, 0,\
                        'FileDescription', 'Gradient fill example',\
                        'LegalCopyright', '(C) Mikolaj Hajduk, 2013',\
                        'FileVersion', PROG_VERSION,\
                        'ProductVersion', PROG_VERSION,\
                        'OriginalFilename', 'GradientFill.exe'

        ; Content of the manifest included as an application resource.
        ;
        resdata man
                db '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'
                db '<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">'
                db '<assemblyIdentity '
                        db 'version="', PROG_VERSION, '" '
                        db 'processorArchitecture="X86" '
                        db 'name="MikolajHajduk.GradientFill" '
                        db 'type="win32"'
                db '/>'
                db '<description>Gradient fill example.</description>'
                db '<dependency>'
                        db '<dependentAssembly>'
                                db '<assemblyIdentity '
                                        db 'type="win32" '
                                        db 'name="Microsoft.Windows.Common-Controls" '
                                        db 'version="6.0.0.0" '
                                        db 'processorArchitecture="X86" '
                                        db 'publicKeyToken="6595b64144ccf1df" '
                                        db 'language="*"'
                                db '/>'
                        db '</dependentAssembly>'
                db '</dependency>'
                db '</assembly>'
        endres
    
The archive containing the source code and executable may be found here. Smile

[EDIT]New version of the program. Main changes:
  • completely new error handling routines have been added,

  • use of local variables stored on the stack and in the extra window memory makes the window procedure reusable,

  • a custom WM_SETGRADIENT message allows to change the default background gradient to a custom one.
[/EDIT]


Last edited by MHajduk on 07 Apr 2013, 21:37; edited 9 times in total
Post 28 Mar 2013, 23:46
View user's profile Send private message Visit poster's website Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 20519
Location: In your JS exploiting you and your system
revolution 29 Mar 2013, 00:01
I realise this is only an example, but I notice that if something fails then you don't always release the bitmap or DC. A potential for memory leaks exists.
Post 29 Mar 2013, 00:01
View user's profile Send private message Visit poster's website Reply with quote
MHajduk



Joined: 30 Mar 2006
Posts: 6115
Location: Poland
MHajduk 29 Mar 2013, 00:10
It would complicate a bit the procedure of the error handling, because we should handle each error differently. I may rethink it, of course, but not now - I am too tired. Wink
Post 29 Mar 2013, 00:10
View user's profile Send private message Visit poster's website Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 20519
Location: In your JS exploiting you and your system
revolution 29 Mar 2013, 00:19
Perhaps something like this:

  1. Upon entry set each handle to zero
  2. Do the allocation and drawing things
  3. Have a common exit point that saves the result code and releases/deletes all handles that are not zero
Post 29 Mar 2013, 00:19
View user's profile Send private message Visit poster's website Reply with quote
MHajduk



Joined: 30 Mar 2006
Posts: 6115
Location: Poland
MHajduk 29 Mar 2013, 00:23
revolution wrote:
Perhaps something like this:

  1. Upon entry set each handle to zero
  2. Do the allocation and drawing things
  3. Have a common exit point that saves the result code and releases/deletes all handles that are not zero
Sounds very rational and is doable for sure. Smile
Post 29 Mar 2013, 00:23
View user's profile Send private message Visit poster's website Reply with quote
bitRAKE



Joined: 21 Jul 2003
Posts: 4162
Location: vpcmpistri
bitRAKE 29 Mar 2013, 03:43
I've always preferred handling WM_ERASEBKGND when a background color is not specified in the class. Mainly because it has a valid DC. I haven't been able to find any concrete information on which method is better.

(I must have some gradient fill code in the archives. IIRC, it filled the buffer directly, but lacks the flexiblity of your example.) Very Happy

_________________
¯\(°_o)/¯ “languages are not safe - uses can be” Bjarne Stroustrup
Post 29 Mar 2013, 03:43
View user's profile Send private message Visit poster's website Reply with quote
AsmGuru62



Joined: 28 Jan 2004
Posts: 1694
Location: Toronto, Canada
AsmGuru62 29 Mar 2013, 14:09
bitRAKE:
But then you paint your window twice:
1. WM_ERASEBKGND - draw the background
2. WM_PAINT - draw the data on painted background.

Two messages.

Another way is to return 1 from WM_ERASEBKGND and paint both
background and data in response to WM_PAINT message.
Post 29 Mar 2013, 14:09
View user's profile Send private message Send e-mail Reply with quote
bitRAKE



Joined: 21 Jul 2003
Posts: 4162
Location: vpcmpistri
bitRAKE 29 Mar 2013, 21:30
AsmGuru62, that is how I understand it as well. Sometimes I don't have a WM_PAINT, or everything can be done from WM_ERASEBKGND - which has already been setup by Windows. (Because Windows is responsible for painting some of the window.)

_________________
¯\(°_o)/¯ “languages are not safe - uses can be” Bjarne Stroustrup
Post 29 Mar 2013, 21:30
View user's profile Send private message Visit poster's website Reply with quote
MHajduk



Joined: 30 Mar 2006
Posts: 6115
Location: Poland
MHajduk 29 Mar 2013, 23:48
bitRAKE wrote:
(I must have some gradient fill code in the archives. IIRC, it filled the buffer directly, but lacks the flexiblity of your example.) Very Happy
It would be interesting to take a look at your code. Smile
Post 29 Mar 2013, 23:48
View user's profile Send private message Visit poster's website Reply with quote
bitRAKE



Joined: 21 Jul 2003
Posts: 4162
Location: vpcmpistri
bitRAKE 30 Mar 2013, 02:00
Code:
GradFill PROC USES ebx esi edi, _HWnd_:DWORD
        LOCAL   Color1:DWORD, Color2:DWORD
        LOCAL   dx1:DWORD, dx2:DWORD, dx3:DWORD
        LOCAL   TmpRect:RECT
        LOCAL   DC:DWORD, FullLength:DWORD

        invoke  GetClientRect, _HWnd_, ADDR TmpRect
        sub             TmpRect.right, 2
        sub             TmpRect.bottom, 2
;calc width of rectangle
        mov             ebx,TmpRect.right
        sub             ebx,TmpRect.left
        mov             FullLength,ebx
        jz              @F
;prepare tmprect
        mov             eax,TmpRect.left
        inc             eax
        mov             TmpRect.right,eax

        invoke  GetWindowLongA,_HWnd_,PWL_GRADDC
        mov             DC,eax
        invoke  GetWindowLongA,_HWnd_,PWL_BARCOLOR1
        mov             Color1,eax
        invoke  GetWindowLongA,_HWnd_,PWL_BARCOLOR2
        mov             Color2,eax

        mov             ecx, Color2
        mov             edi, Color1
        sal             ecx, 7
        sal             edi, 7

        mov             eax, ecx
        mov             ebx, edi
        and             eax, 0FF000000h / 2
        and             ebx, 0FF000000h / 2
        sub             eax, ebx
        cdq
        idiv    FullLength
        mov             dx1, eax

        mov             eax, ecx
        mov             esi, edi
        and             eax, 0FF0000h / 2
        and             esi, 0FF0000h / 2
        sub             eax, esi
        cdq
        idiv    FullLength
        mov             dx2, eax

        mov             eax, ecx
        and             eax, 0FF00h / 2
        and             edi, 0FF00h / 2
        sub             eax, edi
        cdq
        idiv    FullLength
        mov             dx3, eax

        mov             eax, Color1
lp: ;fill tmprect
        invoke  CreateSolidBrush,eax
        push    eax
        invoke  FillRect,DC,ADDR TmpRect,eax ; ADDR destroys EAX!
        call    DeleteObject
;update tmprect
        inc             TmpRect.left
        inc             TmpRect.right

        add     ebx,dx1
        add     esi,dx2
        mov     edx,ebx
        mov     eax,esi
        and     edx,0FF000000h / 2
        and     eax,0FF0000h / 2
        add     edi,dx3
        or      edx,eax

        mov     eax,edi
        and     eax,0FF00h / 2
        or      eax,edx

        shr     eax, 7

        dec     FullLength
        jne     lp
@@:     ret
GradFill ENDP    
It just uses scaled delta values to iterate through the colors between two RGB values. All the needed parameters are from the window (custom control), so it might adapt well to other situations.

_________________
¯\(°_o)/¯ “languages are not safe - uses can be” Bjarne Stroustrup
Post 30 Mar 2013, 02:00
View user's profile Send private message Visit poster's website Reply with quote
hanjin



Joined: 28 Mar 2013
Posts: 13
hanjin 30 Mar 2013, 05:15
Hi. MHajduk!! Wink. It wouldn't compile, fasmw says:

undefined symbol 'WindowProc.wmsize'

I'm using fasmw 1.71.07 .
Post 30 Mar 2013, 05:15
View user's profile Send private message Reply with quote
uart777



Joined: 17 Jan 2012
Posts: 369
uart777 30 Mar 2013, 06:24
MHajduk: Good style. Thanks for the example.

bitRAKE: Why so many divisions and OS-specifics? My draw.fade function draws directly to memory (like text operations) and uses fixed point arithmetic:
Code:
; draw gradual fade from color a to b.
; o/rient: 'h'=horizontal, 'v'=vertical

function draw.fade, o, box, c1, c2
locals x, y, w, h, i, n,\
 r, g, b, r2, g2, b2,\
 nr, ng, nb, first, last

let eax=[box],\
 [x]=[?box.x+eax], [y]=[?box.y+eax],\
 [w]=[?box.w+eax], [h]=[?box.h+eax]

; orientation...

.if [o]='h'
  let eax=[x], [first]=eax, ecx=[w]
.else
  let eax=[y], [first]=eax, ecx=[h]
.end

let [n]=ecx, eax+ecx, [last]=eax

; extract r/g/b components

let eax=&[r], ecx=&[g], edx=&[b]
get.rgb [c1], eax, ecx, edx
let eax=&[r2], ecx=&[g2], edx=&[b2]
get.rgb [c2], eax, ecx, edx

; scale by 256 (2^Cool for accuracy then
; calculate deltas: c2-c1/n

let [r]<<8, [g]<<8, [b]<<8, ecx=[n]

.if ecx
  let eax=[r2], eax<<8, eax-[r], eax/ecx, [nr]=eax,\
   eax=[g2], eax<<8, eax-[g], eax/ecx, [ng]=eax,\
  eax=[b2], eax<<8, eax-[b], eax/ecx, [nb]=eax
.else
  let eax=[r2], eax<<8, eax-[r], [nr]=eax,\
   eax=[g2], eax<<8, eax-[g], [ng]=eax,\
  eax=[b2], eax<<8, eax-[b], [nb]=eax
.end

; draw lines...

.loop [i]=[first] to [last]
  let eax=[r], eax>>8,\
   ecx=[g], ecx>>8, edx=[b], edx>>8
  rgb eax, ecx, edx
  .if [o]='h'
    draw.line.v [i], [y], [h], eax
  .else
    draw.line.h [x], [i], [w], eax
  .end
  let eax=[nr], [r]+eax,\
   ecx=[ng], [g]+ecx,\
  edx=[nb], [b]+edx
.endl
endf    

Or disassembly if you prefer:
Code:
draw.fade:
push ebp                   
mov  ebp,esp
sub  esp,44h               
mov  eax,[ebp+0Ch]
push [eax]
pop  [ebp-44h]
push [eax+4]
pop  [ebp-40h]
push [eax+8]
pop  [ebp-3Ch]
push [eax+0Ch]
pop  [ebp-38h]
cmp  [ebp+8],68h
jne  0040314D              
mov  eax,[ebp-44h]
mov  [ebp-8],eax
mov  ecx,[ebp-3Ch]
jmp  00403156              
mov  eax,[ebp-40h]
mov  [ebp-8],eax
mov  ecx,[ebp-38h]
mov  [ebp-30h],ecx
add  eax,ecx               
mov  [ebp-4],eax
lea  eax,[ebp-2Ch]         
lea  ecx,[ebp-28h]         
lea  edx,[ebp-24h]         
push edx                   
push ecx                   
push eax                   
push [ebp+10h]
call 00402A2A              
lea  eax,[ebp-20h]         
lea  ecx,[ebp-1Ch]         
lea  edx,[ebp-18h]         
push edx                   
push ecx                   
push eax                   
push [ebp+14h]
call 00402A2A              
shl  [ebp-2Ch],8
shl  [ebp-28h],8
shl  [ebp-24h],8
mov  ecx,[ebp-30h]
cmp  ecx,0                 
je   004031C9              
mov  eax,[ebp-20h]
shl  eax,8                 
sub  eax,[ebp-2Ch]
cdq                        
idiv eax,ecx               
mov  [ebp-14h],eax
mov  eax,[ebp-1Ch]
shl  eax,8                 
sub  eax,[ebp-28h]
cdq                        
idiv eax,ecx               
mov  [ebp-10h],eax
mov  eax,[ebp-18h]
shl  eax,8                 
sub  eax,[ebp-24h]
cdq                        
idiv eax,ecx               
mov  [ebp-0Ch],eax
jmp  004031ED              
mov  eax,[ebp-20h]
shl  eax,8                 
sub  eax,[ebp-2Ch]
mov  [ebp-14h],eax
mov  eax,[ebp-1Ch]
shl  eax,8                 
sub  eax,[ebp-28h]
mov  [ebp-10h],eax
mov  eax,[ebp-18h]
shl  eax,8                 
sub  eax,[ebp-24h]
mov  [ebp-0Ch],eax
push [ebp-8]
pop  [ebp-34h]
mov  ecx,[ebp-34h]
cmp  ecx,[ebp-4]
jge  00403256              
mov  eax,[ebp-2Ch]
sar  eax,8                 
mov  ecx,[ebp-28h]
sar  ecx,8                 
mov  edx,[ebp-24h]
sar  edx,8
push edx                   
push ecx                   
push eax                   
call 00402A0E              
cmp  dword [ebp+8],68h
jne  0040322E              
push eax                   
push [ebp-38h]
push [ebp-40h]
push [ebp-34h]
push 76h                   
call 00402FD5              
jmp  0040323F              
push eax                   
push [ebp-3Ch]
push [ebp-34h]
push [ebp-44h]
push 68h                   
call 00402FD5              
mov eax,[ebp-14h]
add [ebp-2Ch],eax
mov ecx,[ebp-10h]
add [ebp-28h],ecx
mov edx,[ebp-0Ch]
add [ebp-24h],edx
inc [ebp-34h]
jmp 004031F3               
mov esp,ebp                
pop ebp                    
ret 10h    
Post 30 Mar 2013, 06:24
View user's profile Send private message Reply with quote
bitRAKE



Joined: 21 Jul 2003
Posts: 4162
Location: vpcmpistri
bitRAKE 30 Mar 2013, 08:10
uart777 wrote:
bitRAKE: Why so many divisions and OS-specifics? My draw.fade function draws directly to memory (like text operations) and uses fixed point arithmetic:
Very Happy I count three IDIV is your code as well.
It was written for Windows, yes. Razz

Have you seen SpAsm/RosAsm? It had a condensed syntax like your code. Although, there doesn't appear to be a website - the wayback machine has a copy of his web site. Or I probably still have an archive of very early versions of SpAsm. There are very dense syntax language like J or K - think they call it data centric languages.

_________________
¯\(°_o)/¯ “languages are not safe - uses can be” Bjarne Stroustrup
Post 30 Mar 2013, 08:10
View user's profile Send private message Visit poster's website Reply with quote
uart777



Joined: 17 Jan 2012
Posts: 369
uart777 30 Mar 2013, 09:10
bitRAKE: Ok, you're right Wink I remember SpAsm/RosAsm. It was created by my old friend Betov. Lost connection with him in 2003? He had good ideas, but I think he let his pride take over and he failed to recognize the bug in his symbol table which Randall Hyde pointed out. Betov pretended that it didn't exist! Whenever I make a mistake, I humbly admit it and I try to correct it.

My language is not based on RosASM in any way.


Last edited by uart777 on 05 Apr 2013, 03:13; edited 1 time in total
Post 30 Mar 2013, 09:10
View user's profile Send private message Reply with quote
uart777



Joined: 17 Jan 2012
Posts: 369
uart777 30 Mar 2013, 10:01
MHajduk: What the hell is this?! Smile
Code:
invoke  LoadIcon, 0, IDI_APPLICATION 
test    eax, eax 
jz      error 
mov     [wc.hIcon], eax    
Do you not know my try syntax simplifies this in one line?
Code:
try [wc.hIcon]=LoadIcon 0, IDI_APPLICATION ; BOOM! That's what's up, NIGGA!!!    
PM me Wink
Post 30 Mar 2013, 10:01
View user's profile Send private message Reply with quote
MHajduk



Joined: 30 Mar 2006
Posts: 6115
Location: Poland
MHajduk 30 Mar 2013, 10:54
hanjin wrote:
Hi. MHajduk!! Wink. It wouldn't compile, fasmw says:

undefined symbol 'WindowProc.wmsize'

I'm using fasmw 1.71.07 .
Hi, hanjin!

The main reason of this is you're using not fully tested releases of fasm (those listed on the lower part of the 'Download' page http://flatassembler.net/download.php of this site). As the description says:
Tomasz Grysztar wrote:
The packages listed below are the latest development snapshot. Note that these versions may not yet be thorougfully tested.
I've compiled my program with the latest stable release, i.e. v. 1.70.03 (see the upper part of the 'Download' page), both with command line compiler and FASMW and haven't noticed any problems. Smile

I recommend to use always the stable releases to avoid potential frustrating problems. Wink
Post 30 Mar 2013, 10:54
View user's profile Send private message Visit poster's website Reply with quote
MHajduk



Joined: 30 Mar 2006
Posts: 6115
Location: Poland
MHajduk 30 Mar 2013, 10:59
uart777 wrote:
MHajduk: What the hell is this?! Smile
Code:
invoke  LoadIcon, 0, IDI_APPLICATION 
test    eax, eax 
jz      error 
mov     [wc.hIcon], eax    
Do you not know my try syntax simplifies this in one line?
Code:
try [wc.hIcon]=LoadIcon 0, IDI_APPLICATION ; BOOM! That's what's up, NIGGA!!!    
PM me Wink
You're asking me what the hell is this... Wink My answer is: both notations belong to the same domain of FASM language and, after compilation, as I suppose, they represent almost the same piece of code. Yeah, your error handling routines may look a bit different but generally we are talking about the same things. Wink
Post 30 Mar 2013, 10:59
View user's profile Send private message Visit poster's website Reply with quote
hopcode



Joined: 04 Mar 2008
Posts: 563
Location: Germany
hopcode 30 Mar 2013, 14:57
RosAsm ?
http://code.google.com/p/rosasm2052f/
i cannot find at the moment some other recent photo-material from Betov, and i dont know whether Betov is the author there on google. i read that code some year ago on that repository. it is worth saving a local copy now with wget.
Cheers,
Very Happy

_________________
⠓⠕⠏⠉⠕⠙⠑
Post 30 Mar 2013, 14:57
View user's profile Send private message Visit poster's website Reply with quote
MHajduk



Joined: 30 Mar 2006
Posts: 6115
Location: Poland
MHajduk 30 Mar 2013, 15:41
Accordingly to revolution's suggestions referring to the emergency cleanup after an error handling I've introduced some changes (additions) to the code. The changed parts you may see below (the entire actual code has been posted in the first post):
Code:
(...)

                ; Actions performed when a portion of the application window needs to be redrawn.
                ;
                .wmpaint:
                        ; Assure that handles of objects used in this part of the application
                        ; window procedure are equal to zero (useful during an emergency cleanup
                        ; when an error occurs).
                        ;
                        mov     [.hdc], 0
                        mov     [.memDC], 0
                        mov     [.memBM], 0

(...)

                ; If anything has gone wrong then display a message box with a proper
                ; error message.
                ;
                .failed:
                        stdcall ShowLastError, [hwnd]

                ; Emergency cleanup operations when something has gone wrong during the
                ; 'WM_PAINT' message processing. Before deleting objects and removing
                ; resources associated with them we have to check if their handles are
                ; valid (i.e. nonzero), because there is a possibility that some of these
                ; objects may be uninitialized.
                ;
                .cleanup:
                        ; Delete the additional unneeded device context.
                        ;
                        cmp     [.memDC], 0
                        je      .memBMdelete

                        invoke  DeleteDC, [.memDC]
                        test    eax, eax
                        jz      .failed

                        ; Release resources occupied by the bitmap associated with the
                        ; application DC.
                        ;
                        .memBMdelete:
                                cmp     [.memBM], 0
                                je      .hdcrelease

                                invoke  DeleteObject, [.memBM]
                                test    eax, eax
                                jz      .failed

                        ; Release the application window device context retrieved by the
                        ; 'GetDC' function call.
                        ;
                        .hdcrelease:
                                cmp     [.hdc], 0
                                je      .wmdestroy

                                invoke  ReleaseDC, [hwnd], [.hdc]
                                test    eax, eax
                                jz      .failed

                ; Operations performed when the application window is to be destroyed.
                ; This is a regular cleanup after receiving the 'WM_DESTROY' message: here
                ; we delete objects and resources allocated during the application window
                ; creation. We don't need to destroy all controls (child windows) manually
                ; because it will be done automatically.
                ;
                ; These operations are also performed when application failed, so it is
                ; also a part of emergency cleanup part above, so we have to check all
                ; handles to be nonzero before proceeding.
                ;
                .wmdestroy:
                        ; Delete the font used to display strings in the application
                        ; window controls.
                        ;
                        cmp     [.hFont], 0
                        je      .quit

                        invoke  DeleteObject, [.hFont]
                        test    eax, eax
                        jz      .failed

                ; Post the 'WM_QUIT' message to the application message queue.
                ;
                .quit:
                        invoke  PostQuitMessage, 0
                        xor     eax, eax

(...)    
Note that we don't need to destroy the application windows controls (button in this case) manually, it would be done for us as it is stated in MSDN:
MSDN wrote:
If the specified window is a parent or owner window, DestroyWindow automatically destroys the associated child or owned windows when it destroys the parent or owner window. The function first destroys child or owned windows, and then it destroys the parent or owner window.
Post 30 Mar 2013, 15:41
View user's profile Send private message Visit poster's website Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 20519
Location: In your JS exploiting you and your system
revolution 30 Mar 2013, 17:27
Well there is still a problem if the cleanup code gets an error. Perhaps you can save and update an error code but still making sure you release all handles, even when something fails.

Although I personally think that for painting there is no need to bother jumping to ".failed". The OS can't paint for you anyway so when you return failed the OS will simply ignore your return code and move to the next item in the message queue. Just power through and release everything regardless of any returned error.
Post 30 Mar 2013, 17:27
View user's profile Send private message Visit poster's website Reply with quote
Display posts from previous:
Post new topic Reply to topic

Jump to:  
Goto page 1, 2, 3  Next

< Last Thread | Next Thread >
Forum Rules:
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Copyright © 1999-2025, Tomasz Grysztar. Also on GitHub, YouTube.

Website powered by rwasa.