The MASM Forum

General => The Workshop => Topic started by: felipe on October 31, 2017, 05:48:44 AM

Title: In the gui path...
Post by: felipe on October 31, 2017, 05:48:44 AM
I decided to work with the petzold book ( ::) yes, you can say i'm an old fashion dude  :bgrin:) to enter more deeply in the windows gui programming.  :exclaim: But as a close reference to the win api functions or windows related topics, no intention to imitate the c programs in the book  :badgrin:.

Here it is the first program based on the first example of that book (.exe attached):

**Wait! the program is in that way writed just for clarity, no big intention i did to do an optimized program**   :redface:

Ok, now have a look:
:biggrin:


; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
; Started by Felipe the 2017-10-29
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

.386
.model      flat,stdcall
option      casemap:none
include     \masm32\include\windows.inc
include     \masm32\include\kernel32.inc
include     \masm32\include\user32.inc
includelib  \masm32\lib\kernel32.lib
includelib  \masm32\lib\user32.lib

.data
align 1
widbuff     byte        4 dup(' ')
heibuff     byte        4 dup(' ')
errotit     byte        'ERROR DETECTED',0
msgerro     byte        'There was an error with the program.',0ah,0dh,\
                        'You can try to use a debugger to watch it.',0
scretit     byte        'SCREEN SIZE IN PIXELS',0
scremsg     byte        'WIDTH: ',4 dup(' '),0ah,0dh,'HEIGHT: ',4 dup(' '),0

.data?
align 4
widthx      dword       ?
heighty     dword       ?

.code
align 4
start:

            push        SM_CXSCREEN                                             ; Get the screeen width in pixels.
            call        GetSystemMetrics                                       

            cmp         eax,0           
            je          erro                                                    ; In case of error show a message and exit.

            mov         widthx,eax                                              ; Store the width here.

            push        SM_CYSCREEN                                             ; Get the screen height in pixels.
            call        GetSystemMetrics

            cmp         eax,0       
            je          erro                                                    ; In case of error show a message and exit.

            mov         heighty,eax                                             ; Store the height here.

            mov         eax,widthx                                              ; Lets process the width first.
            mov         esi,offset widbuff+3                                    ; From the less significant digit.
            mov         ecx,10                                                  ; We divide by 10 to convert the binary
                                                                                ;   into unpacked bcd.

align 4
getbcd:
            xor         edx,edx                                                 ; Cleaning the unpacked bcd temporal storage.
            div         ecx                                                     ; Dividing the width number by 10.   
            mov         [esi],dl                                                ; Moving to the width buffer the less significant digit (u_bcd).   
            dec         esi                                                     ; Next digit (from right to left).
            cmp         eax,ecx                                                 ; If the dividend is greater or equal
            jae         getbcd                                                  ;   to 10 we continue.
            mov         [esi],al                                                ; Moving the most significand digit into the width buffer.

            mov         esi,offset widbuff                                      ; From the most significand digit now.
            mov         edx,4                                                   ; 4 digits cycle.

align 4
getascii:
            or          byte ptr[esi],30h                                       ; Making an unpacked bcd an ascii number.
            inc         esi                                                     ; Next one (from left to right).
            dec         edx                                                     ; Decrement the counter.
            jnz         getascii

            mov         eax,heighty                                             ; Lets process now the height.
            mov         esi,offset heibuff+3                                    ; From the less significant digit.
            mov         ecx,10                                                  ; We divivde by 10 to convert the binary
                                                                                ;   into unpacked bcd.

align 4
getbcd2:
            xor         edx,edx                                                 ; Cleaning the unpacked bcd temporal storage.
            div         ecx                                                     ; Dividing the height number by 10.   
            mov         [esi],dl                                                ; Moving to the height buffer the less significant digit (u_bcd).   
            dec         esi                                                     ; Next digit (from right to left).
            cmp         eax,ecx                                                 ; If the dividend is greater or equal
            jae         getbcd2                                                 ;   to 10 we continue.
            mov         [esi],al                                                ; Moving the most significand digit into the height buffer.

            mov         esi,offset heibuff                                      ; From the most significand digit now.
            mov         edx,4                                                   ; 4 digits cycle.

align 4
getascii2:
            or          byte ptr[esi],30h                                       ; Making an unpacked bcd an ascii number.
            inc         esi                                                     ; Next one (from left to right).
            dec         edx                                                     ; Decrement the counter.
            jnz         getascii2

            mov         esi,offset widbuff                                      ; The most significand digit.   
            cmp         byte ptr[esi],30h                                       ; Is a zero? (like in 800x600: only 3 digits for the width).
            jne         heispace                                                ; If not we now check the height string.
            sub         byte ptr[esi],10h                                       ; Convert that 30h (ascii zero number) into a 20h (ascii space).

align 4
heispace:
            mov         esi,offset heibuff                                      ; The most significand digit.
            cmp         byte ptr[esi],30h                                       ; Is a zero? (like in 800x600: only 3 digits for the height).
            jne         movvar                                                  ; If not we are almost ready to write the string.
            sub         byte ptr[esi],10h                                       ; Convert that 30h (ascii zero number) into a 20h (ascii space).


align 4
movvar:
            mov         edi,offset scremsg+7                                    ; We will put here (in the message box)
            mov         esi,offset widbuff                                      ;  what's here.
            movsd

            mov         edi,offset scremsg+21                                   ; We will put here (in the message box)
            mov         esi,offset heibuff                                      ;  what's here.
            movsd

   
            push        MB_OK                                                   ; Just one button.
            push        offset scretit
            push        offset scremsg
            push        NULL
            call        MessageBox                                              ; Show the screen size in pixels.
            jmp         normal                                                  ; Finish the program.

align 4
erro:
            push        MB_OK
            push        offset errotit
            push        offset msgerro
            push        NULL
            call        MessageBox

align 4
normal:
            push        0
            call        ExitProcess

            end         start
Title: Re: In the gui path...
Post by: felipe on November 04, 2017, 12:31:03 PM
And here it is the next program (based in the next example of the book) The .exe is attached:
:idea:


; ¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤
; This program was started by Felipe in 2017-11-03.
; ¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤


.386
.model      flat,stdcall
option      casemap:none
include     \masm32\include\windows.inc
include     \masm32\include\kernel32.inc
include     \masm32\include\user32.inc
include     \masm32\include\gdi32.inc
includelib  \masm32\lib\kernel32.lib
includelib  \masm32\lib\user32.lib
includelib  \masm32\lib\gdi32.lib

.data
align 1
wndclaname  byte        "EXAMPLE WINDOW CLASS",0                                            ; Name of the window class.
wndname     byte        "WINDOW EXAMPLE",0                                                  ; Title bar of the window.                                                 
msghello    byte        "Well, here it is a way of how to do a window in Windows. ",\
                        "There are many others by the way.",0                               ; Message drawed in the window client area.

.data?
align 4
insthan     dword       ?                                                                   ; Instance handle.
wndclaex    dword       12 dup(?)                                                           ; WNDCLASSEX structure.
wndhand     dword       ?                                                                   ; Window handle.
msgstru     dword       7 dup(?)                                                            ; MSG structure.
hdc         dword       ?                                                                           
painstru    dword       12 dup(?)                                                           ; PAINTSTRUCT structure.
rect        dword       4 dup(?)                                                            ; RECT structure.

.code
align 4
start:
            push        NULL
            call        GetModuleHandle           
            mov         insthan,eax

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
; Fill the WNDCLASSEX structure:

            mov         dword ptr wndclaex[0],sizeof wndclaex                               ; Size of structure.
            mov         dword ptr wndclaex[4],CS_HREDRAW or CS_VREDRAW                      ; Style of class.
            mov         wndclaex[8],wndproc                                                 ; Address of wndproc (callback proc).
            mov         dword ptr wndclaex[12],NULL
            mov         dword ptr wndclaex[16],NULL
            mov         eax,insthan                                                     
            mov         wndclaex[20],eax
            push        500
            push        insthan
            call        LoadIcon
            mov         wndclaex[24],eax
            push        IDC_ARROW
            push        NULL
            call        LoadCursor
            mov         wndclaex[28],eax
            push        WHITE_BRUSH
            call        GetStockObject
            mov         wndclaex[32],eax
            mov         dword ptr wndclaex[36],NULL
            mov         wndclaex[40],offset wndclaname                                      ; Address of the class name.
            mov         dword ptr wndclaex[44],NULL

            push        offset wndclaex                                                     ; Address of the WNDCLASSEX structure.
            call        RegisterClassEx
           
            push        NULL
            push        insthan
            push        NULL
            push        NULL
            push        CW_USEDEFAULT
            push        CW_USEDEFAULT
            push        CW_USEDEFAULT
            push        CW_USEDEFAULT
            push        WS_OVERLAPPEDWINDOW
            push        offset wndname                                                      ; Address of the string displayed in the title bar.
            push        offset wndclaname                                                   ; Address of the WNDCLASSEX structure.
            push        WS_EX_OVERLAPPEDWINDOW
            call        CreateWindowEx
            mov         wndhand,eax                                                         ; Store the window handle.

            push        SW_SHOWNORMAL
            push        eax
            call        ShowWindow

            push        wndhand
            call        UpdateWindow

align 4
msgloop:
            push        0
            push        0
            push        NULL
            push        offset msgstru                                                      ; Address of the MSG structure.
            call        GetMessage
            cmp         eax,0
            je          msgloend

            push        offset msgstru
            call        TranslateMessage                                                    ; For some keyboard processing.

            push        offset msgstru
            call        DispatchMessage                                                     ; Sends a message to a wndproc.
            jmp         msgloop               

align 4
msgloend:                       
            push        dword ptr msgstru[8]
            call        ExitProcess                                                         ; Terminates the program.

align 4
wndproc:
            push        ebp
            mov         ebp,esp
           
            cmp         dword ptr[ebp+12],WM_CREATE
            jne         paint
           
            xor         eax,eax
            mov         esp,ebp
            pop         ebp
            ret         16

align 4
paint:
            cmp         dword ptr[ebp+12],WM_PAINT
            jne         destwnd

            push        offset painstru
            push        wndhand
            call        BeginPaint                                                         

            mov         hdc,eax

            push        offset rect
            push        wndhand
            call        GetClientRect                                                       ; Get the dimensions of the client area.

            push        DT_SINGLELINE or DT_CENTER or DT_VCENTER
            push        offset rect
            push        -1
            push        offset msghello
            push        hdc
            call        DrawText                                                            ; Write a string in the client area.

            push        offset painstru
            push        wndhand
            call        EndPaint

            xor         eax,eax           

            mov         esp,ebp
            pop         ebp
            ret         16

align 4
destwnd:
            cmp         dword ptr[ebp+12],WM_DESTROY
            jne         msgdefau
           
            push        0
            call        PostQuitMessage
           
            xor         eax,eax
            mov         esp,ebp
            pop         ebp
            ret         16

align 4
msgdefau:
            push        dword ptr[ebp+20]
            push        dword ptr[ebp+16]
            push        dword ptr[ebp+12]
            push        dword ptr[ebp+8]
            call        DefWindowProc                                                       ; Default message processing.

            mov         esp,ebp
            pop         ebp
            ret         16
           
            end         start



It's guided in the book's example, is not a copy  :icon_exclaim:. The comments aren't too good because i'm still learning the details of the functions.  :P
Title: Re: In the gui path...
Post by: Mikl__ on November 05, 2017, 12:57:50 AM
¡Hola, Felipe!
If you will use "push WS_OVERLAPPEDWINDOW or WS_VISIBLE" then you do not need
            push        SW_SHOWNORMAL
            push        eax
            call        ShowWindow

            push        wndhand
            call        UpdateWindow
try to do so            push        NULL
            push        insthan
            push        NULL
            push        NULL
            mov         eax,CW_USEDEFAULT
            push        eax
            push        eax
            push        eax
            push        eax
            push        WS_OVERLAPPEDWINDOW or WS_VISIBLE
            push        offset wndname                                                      ; Address of the string displayed in the title bar.
            push        offset wndclaname                                                   ; Address of the WNDCLASSEX structure.
            push        WS_EX_OVERLAPPEDWINDOW
            call        CreateWindowEx
            mov         wndhand,eax                                                         ; Store the window handle.         
            mov         edi,offset msgstru
msgloop:
            push        0
            push        0
            push        NULL
            push        edi                                                      ; Address of the MSG structure.
            call        GetMessage
            or         eax,eax
            je          msgloend

            push        edi
            call        TranslateMessage                                                    ; For some keyboard processing.

            push        edi
            call        DispatchMessage                                                     ; Sends a message to a wndproc.
            jmp         msgloop
P.S. Hi, jj2007! Grazie per l'emendamento!
Title: Re: In the gui path...
Post by: felipe on November 05, 2017, 02:12:27 AM
Thanks Mikl_! I did it and all worked better. I liked those improvements. I certainly want to reach a good optimized assembly programming level.  8)

:icon14: :icon14: :icon14:
Title: Re: In the gui path...
Post by: Mikl__ on November 05, 2017, 03:50:33 AM
Bueno, Philipe, sabía que te gustaría.
invoke GetModuleHandle,NULL
mov x1,eax
invoke LoadIcon,NULL,IDI_APPLICATION
mov x2,eax
        invoke LoadCursor,NULL,IDC_ARROW
mov x3,eax
push x1
push x2
push x3
        push offset fmt 
        push offset buffer     
call wsprintf
        add esp,20
        invoke MessageBox,NULL,addr buffer,addr MsgCaption,MB_OK
        ....
.data
fmt db "hCursor = %04Xh",0Ah,"hIcon = %04Xh",0Ah,"hInstance =%04Xh",0
buffer db 30 dup(?)
x1 dd ?
x2 dd ?
x3 dd ?
Una vez que escriba tal programa, observe qué valores devuelven las funciones GetModuleHandle, LoadIcon y LoadCursor, y no tiene que llamarlas una y otra vez cuando cree un programa de ventana. En tu versión de Windows, estos valores no cambian. Intenta hacer esto ...
Title: Re: In the gui path...
Post by: felipe on November 05, 2017, 07:26:36 AM
The values are:
hCursor:10003h
hIcon:10027h
hInstance:400000h

I don't undestand. Maybe this values are always the same values and i don't have to call the GetModuleHandle function, but if i don't call the other two functions how i will load the icon and the cursor? Or you mean i just have to call them once in each program independently of the number of windows that i create?  :redface:

Title: Re: In the gui path...
Post by: Mikl__ on November 05, 2017, 11:40:59 AM
¡Hola, Felipe!
example for your program; ¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤
; This program was started by Felipe in 2017-11-03.
; ¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤


.386
.model      flat,stdcall
option      casemap:none
include     \masm32\include\windows.inc
include     \masm32\include\kernel32.inc
include     \masm32\include\user32.inc
include     \masm32\include\gdi32.inc
includelib  \masm32\lib\kernel32.lib
includelib  \masm32\lib\user32.lib
includelib  \masm32\lib\gdi32.lib

.data
wndname     byte        "WINDOW EXAMPLE",0                                                  ; Title bar of the window.                                                 
msghello    byte        "Well, here it is a way of how to do a window in Windows. ",\
                        "There are many others by the way.",0                               ; Message drawed in the window client area.

.data?                                                         
wndclaex    WNDCLASSEX <>
msgstru     MSG <>
hdc         dword       ?                                                                           
painstru    PAINTSTRUCT <>
rect        RECT <>
wndhand     dword       ?                                                                   ; Window handle
.code         
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
; Fill the WNDCLASSEX structure:
start:
            mov         wndclaex.cbSize,sizeof wndclaex                        ; Size of structure.
            mov         wndclaex.style,CS_HREDRAW or CS_VREDRAW; Style of class.
            mov         wndclaex.lpfnWndProc,offset wndproc                                                 ; Address of wndproc (callback proc).
            mov         wndclaex.cbClsExtra,NULL
            mov         wndclaex.cbWndExtra,NULL
            mov         wndclaex.hInstance,400000h                                               ; Instance handle
            mov         wndclaex.hIcon,10003h ; icon
            mov         wndclaex.hCursor,10027h ; cursor
            push        WHITE_BRUSH
            call          GetStockObject
            mov         wndclaex.hbrBackground,eax
            mov         wndclaex.lpszMenuName,NULL
            mov         wndclaex.lpszClassName,offset wndname                                      ; Address of the class name.
            mov         wndclaex.hIconSm,10003h

            push        offset wndclaex                                                     ; Address of the WNDCLASSEX structure.
            call          RegisterClassEx
           
            push        NULL
            push        400000h                                                              ; Instance handle
            push        NULL
            push        NULL
            mov         eax,CW_USEDEFAULT
            push        eax
            push        eax
            push        eax
            push        eax
            push        WS_OVERLAPPEDWINDOW or WS_VISION
            push        offset wndname                                                      ; Address of the string displayed in the title bar.
            push        offset wndname                                                   ; Address of the WNDCLASSEX structure.
            push        WS_EX_OVERLAPPEDWINDOW
            call           CreateWindowEx
            mov         wndhand,eax                                                         ; Store the window handle
            mov         edi,offset msgstru                                                      ; Address of the MSG structure
msgloop:
            push        0
            push        0
            push        NULL
            push        edi                                                      ; Address of the MSG structure.
            call        GetMessage
            push        edi
            call        TranslateMessage                                                    ; For some keyboard processing
            push        edi
            call        DispatchMessage                                                     ; Sends a message to a wndproc.
            jmp         msgloop

wndproc:
            push        ebp
            mov         ebp,esp
           
            cmp         dword ptr [ebp+12],WM_CREATE
            je         create
            cmp         dword ptr[ebp+12],WM_PAINT
            je         paint
            cmp         dword ptr[ebp+12],WM_DESTROY
            je         destwnd
msgdefau:
            leave
            jmp        DefWindowProc                                                       ; Default message processing
destwnd:                     
            push        0
            call        ExitProcess                                                         ; Terminates the program
paint:         
            push        offset painstru
            push        wndhand
            call        BeginPaint                                                         
            mov         hdc,eax

            push        offset rect
            push        wndhand
            call        GetClientRect                                                       ; Get the dimensions of the client area.

            push        DT_SINGLELINE or DT_CENTER or DT_VCENTER
            push        offset rect
            push        -1
            push        offset msghello
            push        hdc
            call        DrawText                                                            ; Write a string in the client area.

            push        offset painstru
            push        wndhand
            call        EndPaint
create:
            xor         eax,eax         
            leave
            ret         16                     
            end         start
For your version of Windows, the values for the cursor and the icon will always be the same, so calling the functions of the LoadIcon and LoadCoursor is superfluous. To change the value that the function GetModuleHandle returns, when building the program, if you use the option /BASE:0xNumber  If this option is not used, the default value of Number is 400000h always.
Title: Re: In the gui path...
Post by: felipe on November 05, 2017, 12:02:43 PM
I see. I guess loadicon and loadcursor is just to get those constants. But what if i want a custom icon (like that in the program above, version 1)?

PD: cool stuff, if i store the icon in the cursor location in wndclass and viceversa i get in the client area of the window the icon for the program as the cursor.  :lol:

Also i suppose that to run the program in another version of windows i will have to use those functions, right?
Title: Re: In the gui path...
Post by: Mikl__ on November 05, 2017, 12:06:39 PM
You will use those functions for to run the program in another version of windows, it is right. The version of Windows is like fashion. Most users (90%) have the same version of Windows. About icons and cursors
Quoteif i store the icon in the cursor location in wndclass and viceversa i get in the client area of the window the icon for the program as the cursor
you look in Chapter #11. Brer Rabbit studies icons and cursors (https://wasm.in/threads/skazki-djadjushki-rimusa.31832/page-2#post-383779)
Title: Re: In the gui path...
Post by: hutch-- on November 05, 2017, 12:40:58 PM
There are some things that I always make GLOBAL, the instance handle, main window handle, icon and cursor handles and any of those things that only need to be loaded once. If you are calling either external files like a DLL or a library module, you pass any of them as required. Things like this are determined at the scope level, things that you need as LOCAL within a procedure are easily dealt with as locals where data that is required across many different parts of an application are best dealt with as GLOBAL scope variables.

It was fashion in the early to middle 1990s to desperately avoid using GLOBAL variables as a prelude to OOP coding but it also produced some terrible code with multiple duplications of simple things like getting the instance handle "invoke GetModuleHandle,0" when you only ever needed to do this once and store it at GLOBAL scope. Also be careful about using the constant as the instance handle as this can be altered by the linker, one API call will not blow out the file size and it is the safe way to do it.
Title: Re: In the gui path...
Post by: Mikl__ on November 05, 2017, 12:46:55 PM
Good morning, hutch--!
you are right, but usually assembler programs are written for author-self, and not for commercial distribution, therefore I gave these advice to Felipe
Title: Re: In the gui path...
Post by: felipe on November 05, 2017, 01:17:10 PM
Indeed i think is a very nice information about the windows system (great page).
But yes, for doing programs for others it's better to use the api calls that do the jobs.

:icon14: :icon14:

Title: Re: In the gui path...
Post by: jj2007 on November 05, 2017, 02:27:58 PM
Quote from: felipe on November 05, 2017, 01:17:10 PMfor doing programs for others it's better to use the api calls that do the jobs.

Just imagine that in a year or two, your computer gets stolen and your new machine has Windows 11 installed. Do you want to rewrite all your code?
Title: Re: In the gui path...
Post by: Mikl__ on November 05, 2017, 03:21:00 PM
Buona mattina, jj2007!
I'm not Michelangelo di Lodovico di Leonardo di Buonarroti Simoni and my programs will become obsolete in a year and I will not write any more as I would write a year ago. And there will be commands that will no longer support new processors that were two or five years ago. Programming in assembler is fast ... and I do not need to rewrite ALL the code I wrote a year ago
Title: Re: In the gui path...
Post by: hutch-- on November 05, 2017, 03:55:00 PM
I tend to walk a hard line here, there will always be hobbyist code that people use locally to get a job done and I have a reasonable amount of "Write once, Run once" code that I use a basic compiler for which I can pelt out in a few minutes to do things like write tables and similar messy things to write manually but there are only 2 classes of code that gets released, professional class high reliability binaries and TRASH.

The vast number of people who have written MASM code over the years need it for something serious and it must be professional quality and this means using properly documented functions (API and some VC runtime code), code that fully complies with the ABI for the platform (Intel for win32 and Microsoft for Win 64) and algorithm code that has had the guts kicked out of it to ensure that it is reliable across multiple versions of Windows. With 64 bit you can safely use most of the later instructions but you need to do a CPUID test if you want to use the latest SSE4.2 and AVX and later instructions.

Stay away from later OS versions of specific API code if you can do it with an earlier API as it will run on more processors and OS versions and write tricks and undocumented functions at your own risk as there is no reason to think they will be supported in later OS versions. The other thing that cannot be overstressed is understand and stick to the published ABI register usages as this has been reliable since the start of Win32. Same with Win 64, you have a Microsoft ABI on which registers to use and which to protect and if you get it wrong, it will explode in your face and make you look like a jerk who doesn't understand the OS specifications.
Title: Re: In the gui path...
Post by: jj2007 on November 05, 2017, 08:42:57 PM
Quote from: Mikl__ on November 05, 2017, 03:21:00 PMmy programs will become obsolete in a year and I will not write any more as I would write a year ago. And there will be commands that will no longer support new processors that were two or five years ago

Carissimo Mikl,

A quick file search for the *.asc ending finds over 5,000 files in my \Masm32 folder, the oldest being about 10 years old. If one of them doesn't build by hitting F6, alarm bells ring in my head, and I start investigating what may have changed. Same for GfaBasic files with the *.gfw extension, they build fine even if they date back 40 years.

You may call that paranoid, but it distinguishes a serious coder from a trial-and-error script kiddie. You are not in the latter category, you have proven that you can produce great stuff here, especially with the Iczelion tutorials that you ported to 64-bit land. Google mikl Iczelion to see what I mean. People value your work.

The ability to build code that is more than a year old is also something that distinguishes the Masm32 SDK from "professional" packages like Visual Studio. The main reason why I don't take Micros**t seriously is indeed that everytime I find a little hello world proggie on the web that is older than, say: 2 years, and I try to load it into Visual Crap, the M$ flagship complains whiningly that it is unable to open such old stuff. Or it simply hangs. That is truely "professional", but guess what, we can do better, and we are proud of that :icon_mrgreen:

In short: Read carefully what Hutch writes above. He is 100% right ;-)

P.S.: "there will be commands that will no longer support new processors" - very unlikely. M$ is scared of breaking legacy code, and Intel/AMD sell CPUs for the M$ world. Even dinosaurs like lodsb and jecxz work just fine in 64-bit code (but aaa aad aam don't, see x64 Instructions (https://docs.microsoft.com/en-us/windows-hardware/drivers/debugger/x64-instructions)). Of course, one has to draw a line somewhere - nobody here wants to support Windows 95. My rule with MasmBasic is to use SSE2 and below in library routines, which means it is fast enough and will run on 99.x% of all machines. Similar for API calls: XP must support it; if a user decides that a Vista API call is needed, so be it - he is free to do that in "pure" assembly, but a library should give a high weight to compatibility (one reason btw why Linux never got a foot in the door).
Title: Re: In the gui path...
Post by: felipe on November 06, 2017, 01:28:15 PM
Quote from: jj2007 on November 05, 2017, 08:42:57 PM
nobody here wants to support Windows 95.

:lol:

=======================================================================
I'm agreed with all of you, basically because you all know the difference between building windows's "standard applications" and something particular. The later can be of different kinds. Of course the later type also should be based in reasonable knowledge and experience. By just trying things and see what happen later it will be probably a loose of time (at least for someone). But i do support to professionals (and with that i just mean someone who understand what he/she is doing) with some special works. They may not run in more than a few machines, but that's precisely one of the main advantages of assembly programming: the specific thing. Of course most will say is a disadvantage.
You all also know how OS specific it is, so yeah if someone want's to try more special things and is an assembly programmer  :P, if he/she knows what he/she is doing, so ok. If you don't know, don't loose your time in that way. First learn how things really work, then explore but based in what you already know of course.
Well at least that's how i work...

:icon14: :icon14:
Title: Re: In the gui path...
Post by: felipe on December 13, 2017, 02:19:34 PM
I had been very bussy, but now i have more time to work on my codings. Here it is a premature version of what should be a more complete version of the next example program just based in the book. Remember, just based, is not a copy, it's just a guide.
The .exe is attached.


; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
; This program was started by Felipe at 2017-12-12.
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

.386
.model      flat,stdcall
option      casemap:none

include     \masm32\include\windows.inc
include     \masm32\include\kernel32.inc
include     \masm32\include\user32.inc
include     \masm32\include\gdi32.inc
includelib  \masm32\lib\kernel32.lib
includelib  \masm32\lib\user32.lib
includelib  \masm32\lib\gdi32.lib



.data
align 1
claname     byte        "TEXT CLASS",0
wndname     byte        "A WEIRD TEXT-GRAPHIC (WHAT?) PROGRAM JUST FOR ALL OF YOU!",0
textmsg     byte        "Hello friends, this is a very simple program. You can see it, hate it or laught of it."
            byte        "It's your choice...                                                                   "
            byte        "I'm working with that old (may i say old?) book from Petzold, but i had to write this "
            byte        "before  i finish the example that i'm studying.                                       "
            byte        "In my opinion, or IMHO, GDI looks pretty cool stuff.                                  "
            byte        "I hope you can visualize this text closely to normal, since i'm not trying to adjust  "
            byte        "in the program nothing related to your system metrics. Sorry for that, you know i'm a "
            byte        "beginner.                                                                             "
            byte        "Hey, i had an idea!: From now on all my post and replies will be in a window program  "
            byte        "like this one, with my opinions hardcoded in a text like this...                      "
            byte        "You will have to download them and ...HAHAHAHA!!! You will hate me more, right?       "                                       
            byte        "Ok, no more jokes.                                                                    "


.data?
align 4
hmodule     dword       ?
wndclaex    dword       12 dup(?)                                                       ; The WNDCLASSEX structure.
hwnd        dword       ?
msgstru     dword       7 dup(?)                                                        ; The MSG structure.
hdc         dword       ?
paintstru   dword       12 dup(?)                                                       ; The PAINTSTRUCT structure. 


.code
align 4
start:
            push        NULL
            call        GetModuleHandle
            mov         hmodule,eax

            mov         dword ptr wndclaex[0],sizeof wndclaex
            mov         dword ptr wndclaex[4],CS_HREDRAW or CS_VREDRAW
            mov         dword ptr wndclaex[8],wndproc
            mov         dword ptr wndclaex[12],0
            mov         dword ptr wndclaex[16],0
            mov         wndclaex[20],eax
            push        500
            push        eax
            call        LoadIcon
            mov         wndclaex[24],eax
            push        IDC_ARROW
            push        NULL
            call        LoadCursor
            mov         wndclaex[28],eax
            push        WHITE_BRUSH
            call        GetStockObject
            mov         wndclaex[32],eax
            mov         dword ptr wndclaex[36],NULL
            mov         dword ptr wndclaex[40],offset claname   
            mov         dword ptr wndclaex[44],NULL

            push        offset wndclaex
            call        RegisterClassEx

            push        NULL
            push        hmodule
            push        NULL
            push        NULL
            push        CW_USEDEFAULT
            push        CW_USEDEFAULT
            push        CW_USEDEFAULT
            push        CW_USEDEFAULT
            push        WS_OVERLAPPEDWINDOW
            push        offset wndname       
            push        offset claname
            push        WS_EX_OVERLAPPEDWINDOW
            call        CreateWindowEx
            mov         hwnd,eax

            mov         esi,eax

            push        SW_SHOWNORMAL
            push        esi
            call        ShowWindow

            push        esi
            call        UpdateWindow

            mov         esi,offset msgstru


align 4
msgloop:

            push        0
            push        0
            push        NULL
            push        esi
            call        GetMessage
            cmp         eax,0
            jz          endmsglop

            push        esi
            call        TranslateMessage

            push        esi
            call        DispatchMessage

            jmp         msgloop


align 4
endmsglop:
           
            push        dword ptr[esi+8]
            call        ExitProcess


align 4
wndproc:

            push        ebp
            mov         ebp,esp
         
            cmp         dword ptr[ebp+12],WM_PAINT
            jne         destroy

            push        offset paintstru
            push        hwnd
            call        BeginPaint
            mov         hdc,eax

            push        00e00000h                                                           ; Blue color for the text.
            push        eax
            call        SetTextColor

            mov         esi,offset textmsg
            xor         edi,edi                                                             ; The y coordinate.
            mov         ebx,12                                                              ; Number of lines.
           
         


align 4
allstri:
            push        86                                                                  ; Number of characters per line.
            push        esi                                                                 ; Line addresses.   
            push        edi                                                                 ; Y coordinate.   
            push        0                                                                   ; X coordinate.
            push        hdc
            call        TextOut
           
            add         edi,25                                                              ; Increase y coordinate.       
            add         esi,86                                                              ; Get the address of the next line of text.
            dec         ebx                                                                 ; Decrease the total of lines to print (draw).
            jnz         allstri                                                             ; Repeat until all the string are drawed.   
                               
            push        offset paintstru
            push        hwnd
            call        EndPaint

            xor         eax,eax

            mov         esp,ebp
            pop         ebp

            ret         16


align 4
destroy:

            cmp         dword ptr[ebp+12],WM_DESTROY
            jne         wnddefau
           
            push        0
            call        PostQuitMessage

            xor         eax,eax

            mov         esp,ebp
            pop         ebp

            ret         16


align 4
wnddefau:

            push        dword ptr[ebp+20]
            push        dword ptr[ebp+16]
            push        dword ptr[ebp+12]
            push        dword ptr[ebp+8]
            call        DefWindowProc

            mov         esp,ebp
            pop         ebp

            ret         16

            end         start


Title: Re: In the gui path...
Post by: jj2007 on December 13, 2017, 07:22:47 PM
You could refine it and make it more efficient if you create the WNDCLASSEX structure directly on the stack:  push NULL ; last arg of CreateWindowEx
  push NULL
  call GetModuleHandle
  push eax ; 2nd last arg of CreateWindowEx
  push 32512
  push eax
  xchg eax, ebx
  call LoadIcon
  push NULL ; wndclaex[44]
  push offset claname
  push NULL ; wndclaex[36]
  push WHITE_BRUSH
  call GetStockObject
  push eax ; wndclaex[32]
  push IDC_ARROW
  push NULL
  call LoadCursor
  push eax ; wndclaex[28]
  push 32512
  push ebx
  call LoadIcon
  push eax ; wndclaex[24]
  push ebx ; wndclaex[20]
  push 0 ; wndclaex[16]
  push 0 ; wndclaex[12]
  push wndproc
  push CS_HREDRAW or CS_VREDRAW
  push WNDCLASSEX
  push esp
  call RegisterClassEx
  push NULL
  push NULL
  push CW_USEDEFAULT
  push CW_USEDEFAULT
  push CW_USEDEFAULT
  push CW_USEDEFAULT
  push WS_OVERLAPPEDWINDOW
  push offset wndname
  push offset claname
  push WS_EX_OVERLAPPEDWINDOW
  call CreateWindowEx
  add esp, WNDCLASSEX
Title: Re: In the gui path...
Post by: felipe on December 14, 2017, 04:02:25 AM
Man, i like it and i understood the sequence, but i'm a little confused with this:  :redface:

  push WNDCLASSEX           ; How this could give us
  push esp                          ;    the size of the structure?
 
And this:

add esp, WNDCLASSEX        ; Wow is possible to do this! (I already have assemble the code without errors).

I will check the code in a moment with a debugger to understand this three statments (instructions) later. I guess you were assuming a local wndclassex, but it make no sense for me by now, because looks like you don't use that local space. I mean you are using part of it but not all of it (maybe all the program is local?).
I will try it with a debugger in a moment. Thanks btw, i think it's a great job!  :icon14:
(But i need to know it for sure)  :biggrin:
Title: Re: In the gui path...
Post by: felipe on December 14, 2017, 05:16:40 AM
Ok jj i solved the puzzle:  :biggrin:

push WNDCLASSEX           ; The size of the structure (in bytes).
push esp                          ; The starting address of the structure (wich is in the stack).

then:

add esp, WNDCLASSEX     ; Discarding the structure from the stack.

But this later statement most be located inmediately  after registering the class and before continuing pushing the remainders parameters for the CreateWindowsEx function.

You are a hard teacher... :redface:

:P

Btw, one more thing: I'm still confused how WNDCLASSEX can be interpreted as a number of bytes. This only happen when we push the structure in the stack?, Why use sizeof if not? You have to admit that this is weird and if not, please explain me that.  :greensml:

Thanks.
:icon14:
Title: Re: In the gui path...
Post by: jj2007 on December 14, 2017, 06:46:47 AM
Quote from: felipe on December 14, 2017, 05:16:40 AMI'm still confused how WNDCLASSEX can be interpreted as a number of bytes.

WNDCLASSEX, RECT, DWORD etc are structures or types, but they are also just immediate numbers. Test it:include \masm32\include\masm32rt.inc
.code
sometest proc
  ret
sometest endp
start:
  print str$(BYTE), 9, "a byte", 13, 10
  print str$(REAL8), 9, "a Real8", 13, 10
  print hex$(sometest)," a proc", 13, 10
  print hex$(WNDCLASSEX), " a struct", 13, 10
  print str$(sometest), 9, "a proc", 13, 10
  inkey str$(WNDCLASSEX), 9, "a struct", 13, 10
  exit
end start


1       a byte
8       a Real8
00401000 a proc
00000030 a struct
4198400 a proc
48      a struct
Title: Re: In the gui path...
Post by: felipe on December 14, 2017, 07:30:20 AM
Cool stuff! Immediate numbers indicating the size in bytes of each one. So they should be just labels for the assembler for indicating to it how many bytes to store, reserve, etc. Nice to know this.

Quote from: felipe on December 14, 2017, 05:16:40 AM

You are a hard teacher... :redface:

:P


As a matter of fact you are a very good one.  ;) Thanks.
:t