News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests

Main Menu

Tamagotchi. Finite-state machine

Started by Mikl__, December 19, 2015, 01:50:02 PM

Previous topic - Next topic

Mikl__

Tamagotchi. Finite-state machine
asm-file; masm windows gui #
.686   
.model flat
      ;include c:\masm32\include\windows.inc
      include c:\masm32\include\gdi32.inc
      include c:\masm32\include\user32.inc
      include c:\masm32\include\kernel32.inc
      include c:\masm32\include\oleaut32.inc
      include c:\masm32\include\ole32.inc
      includelib c:\masm32\lib\gdi32.lib
      includelib c:\masm32\lib\user32.lib
      includelib c:\masm32\lib\kernel32.lib
      includelib c:\masm32\lib\oleaut32.lib
      includelib c:\masm32\lib\ole32.lib

BitmapFromPicture PROTO   :DWORD
BitmapFromMemory        PROTO :DWORD,:DWORD


WS_EX_TOPMOST                        equ 8
WS_CHILD                             equ 40000000h
SW_SHOWNORMAL                        equ 1
WM_COMMAND                           equ 111h
SW_SHOWDEFAULT                       equ 10
WM_LBUTTONDOWN                       equ 201h
TRANSPARENT                          equ 1
DT_SINGLELINE                        equ 20h
HIMETRIC_INCH       EQU     2540
exebase equ 400000h
TRUE                                 equ 1
SM_CYSCREEN                          equ 1
SM_CYCAPTION                         equ 4
SM_CXDLGFRAME                        equ 7
SM_CYDLGFRAME                        equ 8
SRCCOPY                              equ 0CC0020h
E_POINTER                            equ 80004003h
E_OUTOFMEMORY                        equ 8007000Eh
E_INVALIDARG                         equ 80070057h
E_FAIL                               equ 80004005h
WM_PAINT                             equ 0Fh
WM_DESTROY                           equ 2h
WS_VISIBLE                           equ 10000000h
WS_POPUP                             equ 80000000h
WS_EX_LEFT                           equ 00000000h
ERROR_FILE_NOT_FOUND                 equ 2
ERROR_INVALID_PARAMETER              equ 87
COLOR_BTNFACE                        equ 15
WS_CAPTION                           equ 0C00000h
WS_SYSMENU                           equ 80000h
LOGPIXELSX                           equ 88
LOGPIXELSY                           equ 90
DT_VCENTER                           equ 4h
DT_CENTER                            equ 1h
ID_JPG1 equ 1
ID_JPG2 equ 2
ID_JPG3 equ 3
ID_JPG4 equ 4
ID_JPG5 equ 5
ID_JPG6 equ 6
ID_BTN_EXIT     equ 100

POINT STRUCT
  x DWORD ?
  y DWORD ?
POINT ENDS

RECT STRUCT
  left    dd      ?
  top     dd      ?
  right   dd      ?
  bottom  dd      ?
RECT ENDS

MSG STRUCT
  hwnd      DWORD      ?
  message   DWORD      ?
  wParam    DWORD      ?
  lParam    DWORD      ?
  time      DWORD      ?
  pt        POINT      <>
MSG ENDS

PAINTSTRUCT STRUCT
  hdc           DWORD      ?
  fErase        DWORD      ?
  rcPaint       RECT       <>
  fRestore      DWORD      ?
  fIncUpdate    DWORD      ?
  rgbReserved   BYTE 32 dup(?)
PAINTSTRUCT ENDS

IPicture STRUCT
    ; IUnknown methods
    QueryInterface          DWORD   ?
    AddRef                  DWORD   ?
    Release                 DWORD   ?
    ; IPicture methods
    get_Handle              DWORD   ?
    get_hPal                DWORD   ?
    get_Type                DWORD   ?
    get_Width               DWORD   ?
    get_Height              DWORD   ?
    Render                  DWORD   ?
    set_hPal                DWORD   ?
    get_CurDC               DWORD   ?
    SelectPicture           DWORD   ?
    get_KeepOriginalFormat  DWORD   ?
    put_KeepOriginalFormat  DWORD   ?
    PictureChanged          DWORD   ?
    SaveAsFile              DWORD   ?
    get_Attributes          DWORD   ?
IPicture ENDS

.code
start:


xor ebx,ebx
mov esi,exebase
mov edi,offset wTitle
push offset CursorFile
call LoadCursorFromFileA
push edi
push ebx
push COLOR_BTNFACE+1
push eax
push eax
push esi
push ebx
push ebx
push offset WndProc
push ebx
push esp
call RegisterClassA

mov ecx,Cpt
mov eax,[WinW+ecx*4-4]
mov x2Reg,eax
mov eax,[WinH+ecx*4-4]
mov y2Reg,eax
push SM_CYDLGFRAME
call GetSystemMetrics
mov y1Reg,eax
add y2Reg,eax
shl eax,1
add WinH,eax
add WinW,eax
push SM_CXDLGFRAME
call GetSystemMetrics
mov x1Reg,eax
inc eax
add x2Reg,eax
    ; Hauteur du bandeau titre
    ; ------------------------
push SM_CYCAPTION
    call GetSystemMetrics
    add WinH,eax
    add y1Reg,eax
    inc eax
    add y2Reg,eax
    ; Obtenir la largeur en pixels de l'ecran
    ; ---------------------------------------
push ebx;SM_CXSCREEN
    call GetSystemMetrics
    mov WScreen,eax
    sub eax,WinW
    shr eax,1
    mov WinX,eax
    ; Obtenir la hauteur en pixels de l'ecran
    ; ---------------------------------------
        push SM_CYSCREEN
    call GetSystemMetrics
    mov HScreen,eax
    sub eax,WinH
    shr eax,1
    mov WinY,eax
;--------------------------+
; creating the main window |
;--------------------------+
restart: mov eax,Cpt
        mov esi,exebase
mov edi,offset wTitle
push ebx
push esi
push ebx
push ebx
push [WinH+eax*4-4]
push [WinW+eax*4-4]
push WinY
push WinX
push WS_CAPTION+WS_SYSMENU
push edi
push edi
push WS_EX_LEFT or WS_EX_TOPMOST
call CreateWindowExA
mov hWnd,eax
        mov ecx,Cpt
mov eax,[WinW+ecx*4-4]
mov x2Reg,eax
mov eax,[WinH+ecx*4-4]
mov y2Reg,eax
push 100
push 100
push y2Reg
push x2Reg
push y1Reg
push x1Reg
call CreateRoundRectRgn
push ebx
push eax
push hWnd
call SetWindowRgn
push SW_SHOWDEFAULT
push hWnd
call ShowWindow
call BitmapFromResource
        mov hBmp, eax
        mov eax,Cpt
mov eax,[WinW+eax*4-4]
sub eax,60
push ebx
push exebase
push ID_BTN_EXIT
push hWnd
push 18
push 20
push 18
push eax
push WS_CHILD or WS_VISIBLE
push offset lpText
push offset btnClass
push ebx
        call CreateWindowEx
  ; ---------------------------
  ; macros for unchanging code
  ; ---------------------------
mov ebp,esp
StartLoop:push ebx
push ebx
push ebx
push ebp
      call GetMessage
or eax,eax
jz ExitProgram
push ebp
      call DispatchMessage
jmp StartLoop
ExitProgram:cmp ClickMouse,ebx
       jz a0
       inc Cpt
       mov eax,Cpt
       jmp [handler+eax*4-8]
a1:    mov WinX,10
       jmp a6
a2:    mov eax,WScreen
       sub eax,WinW
       sub eax,160
       mov WinX,eax
       jmp a6
a3:    mov WinX,10
       mov eax,HScreen
       sub eax,WinH
       sub eax,160
       jmp a7
a4:    mov eax,WScreen
       sub eax,[WinW+3*4]
       shr eax,1
       mov WinX,eax
       mov eax,HScreen
       sub eax,[WinH+3*4]
       shr eax,1
a7:    mov WinY,eax
       jmp restart
a5:    mov eax,WScreen
       sub eax,[WinW+4*4]
       shr eax,1
       mov WinX,eax
a6:    mov WinY,ebx;0
       jmp restart
a0: push ebx
call ExitProcess



WndProc proc hWin,uMsg,wParam,lParam

    LOCAL hOld:DWORD
    LOCAL ps:PAINTSTRUCT

    mov eax,uMsg
mov edi,hWin
sub eax,WM_DESTROY
jz wmDESTROY
sub eax,WM_PAINT-WM_DESTROY
jz wmPAINT
sub eax,WM_COMMAND-WM_PAINT
jz wmCOMMAND
sub eax,WM_LBUTTONDOWN-WM_COMMAND
jz wmLBUTTONDOWN
leave
jmp DefWindowProc
wmDESTROY:mov ClickMouse,ebx
jmp @f
wmCOMMAND: cmp wParam,ID_BTN_EXIT
jne wmBYE
push ebx
push ebx
push WM_DESTROY
push edi
call PostMessage
jmp wmBYE
wmLBUTTONDOWN:push edi
call DestroyWindow
inc ClickMouse
@@: push ebx
call PostQuitMessage
jmp wmBYE
wmPAINT:lea eax,ps
push eax
push edi
    call BeginPaint
    push eax;hDC
    call CreateCompatibleDC
    mov esi,eax
    push hBmp
    push eax
    call SelectObject
    mov hOld,eax
    mov eax,Cpt
push SRCCOPY
push ebx;0
push ebx;0
push esi;memDC
push [WinH+eax*4-4]
push [WinW+eax*4-4]
push 1
push ebx
push ps.hdc
call BitBlt
push TRANSPARENT
push ps.hdc
        call SetBkMode
        mov eax,Cpt
push DT_SINGLELINE+DT_VCENTER+DT_CENTER
push offset rectTxt
push -1
push dword ptr [handler2+eax*4-4]
push ps.hdc
        call DrawText
push ps.hdc
call SelectObject
push esi;memDC
    call DeleteDC
lea eax,ps
    push eax;ADDR ps
    push edi;hWin
call EndPaint
wmBYE:    ret

WndProc endp
BitmapFromResource  PROC
    LOCAL hResource:DWORD,  dwFileSize:DWORD, hImage:DWORD

    ; get a resource handle (address) and resource length from the executable
push offset szImage
push Cpt
push esi
    call FindResource
    or eax,eax
    jz error
    mov hResource, eax
push eax
push esi
    call LoadResource
push eax
    call LockResource
    mov hImage, eax
push hResource
push esi
    call SizeofResource
    mov dwFileSize, eax
    or eax,eax      ; we use the resource size to determine if we got a
        jz error        ; legit image file to open
push dwFileSize
push hImage
        call BitmapFromMemory
    jmp @f
error: push ERROR_FILE_NOT_FOUND
        call SetLastError
        xor eax,eax
@@:     ; everything's been done for us now, just return
    ret                     ; we're all done

BitmapFromResource  ENDP   

BitmapFromMemory  PROC uses esi edi pMemory:DWORD, dwFileSize:DWORD

    LOCAL hResource:DWORD,  pGlobal:DWORD,      pStream:DWORD
    LOCAL hImage:DWORD,     pPicture:DWORD,     hBitmap:DWORD

   ;invoke CoInitialize, ebx
    mov pStream, ebx
    mov pPicture, ebx    ; ebx pointers for later use
    invoke CoTaskMemAlloc, dwFileSize   ; copy picture into task memory
    or eax,eax
jz error
        ; oops! we didn't get the memory
        ; the last error code was set for us, and EAX is zero, so just return

    mov pGlobal, eax
    mov esi, pMemory
    mov edi, eax;pGlobal
    mov ecx, dwFileSize
push ecx
    shr ecx, 2
    rep movsd
        pop ecx
    and ecx, 11y
    rep movsb

    ; create a stream for the picture object's creator
    invoke CreateStreamOnHGlobal, pGlobal, TRUE, ADDR pStream
    or eax,eax
    jz @f
    invoke CoTaskMemFree,pGlobal
    xor eax,eax
    jmp error
   
@@: lea eax,pPicture
push eax
push offset IID_IPicture
push TRUE
push ebx
push pStream
call OleLoadPicture
    or eax,eax
    jz @f
    mov eax, pStream
    call release_pStream
    xor eax,eax
    jmp error

@@:   
    ; now we are ready to get the hBipmap, we farm this out for reuseability
    invoke BitmapFromPicture, pPicture
    mov hBitmap, eax 

    mov eax, pStream
    call release_pStream

    mov eax, pPicture
    call release_pPicture

    mov eax, hBitmap                ; hBitmap is our return value, stuff it

error:    ret                             ; we're all done

BitmapFromMemory ENDP

; release the stream
release_pStream PROC
    push eax
    mov eax, [eax]
    call [eax].IPicture.Release   
    ret
release_pStream ENDP

; release the Picture object
release_pPicture PROC
    push eax
    mov eax, [eax]
    call [eax].IPicture.Release   
    ret
release_pPicture ENDP

BitmapFromPicture PROC pPicture:DWORD
    LOCAL tempDC:DWORD,  tempBitmap:DWORD,  OldBitmap:DWORD
    LOCAL dwWidth:DWORD, dwHeight:DWORD,    compDC:DWORD
    LOCAL hmWidth:DWORD, hmHeight:DWORD,    neghmHeight:DWORD

    ; check we have an object
    cmp pPicture,0
jnz @f
        ; whoops, no object passed in
push ERROR_INVALID_PARAMETER
        jmp seterror
@@:   
    ; get a DC to work with
    invoke GetDC, ebx          ; screen DC
    mov compDC, eax
    invoke CreateCompatibleDC, compDC
    or eax,eax
jnz @f
        ; whoops, didn't get a DC
        ; but at least we had SetLastError called for us
        invoke ReleaseDC,ebx,compDC
        jmp error
@@:    mov tempDC, eax

    ; read out the width and height of the IPicture object
    ; (IPicture)pPicture::get_Width(*hmWidth)
    lea eax, hmWidth
    push eax
    mov eax, pPicture
    push eax
    mov eax, [eax]
    call [eax].IPicture.get_Width

    ; (IPicture)pPicture::get_Height(*hmHeight)
    lea eax, hmHeight
    push eax
    mov eax, pPicture
    push eax
    mov eax, [eax]
    call [eax].IPicture.get_Height

    ; convert himetric to pixels
    invoke GetDeviceCaps, compDC, LOGPIXELSX
    invoke MulDiv, hmWidth, eax, HIMETRIC_INCH
    mov dwWidth, eax

    invoke GetDeviceCaps, compDC, LOGPIXELSY
    invoke MulDiv, hmHeight, eax, HIMETRIC_INCH
    mov dwHeight, eax
    xor eax, eax
    sub eax, hmHeight
    mov neghmHeight, eax

    invoke CreateCompatibleBitmap, compDC, dwWidth, dwHeight
    or eax,eax;.IF !eax
jz err
        ; whoops, didn't get a bitmap
        ; but at least we had SetLastError called for us\
        ; clean up the DC
mov tempBitmap, eax

    invoke SelectObject, tempDC, tempBitmap
    or eax,eax;.IF !eax
jnz @f
        ; whoops, didn't select our bitmap
        ; but at least we had SetLastError called for us
        invoke DeleteObject, tempBitmap
err:    invoke ReleaseDC,ebx,compDC
        invoke DeleteDC, tempDC

        jmp error
@@:    mov OldBitmap, eax

    ; ok, now we have our bitmap mounted onto our temporary DC, let's blit to it
    ; (IPicture)pPicture::Render(hdc, x, y, cx, cy,                            \
    ;                            xpos_himetric, ypos_himetric,                 \
    ;                            xsize_himetric, ysize_himetric, *rectBounds)
    push ebx   ; *rectBounds
    push neghmHeight
    push hmWidth
    push hmHeight
    push ebx;0
    push dwHeight
    push dwWidth
    push ebx;0
    push ebx;0
    push tempDC
    mov eax, pPicture
    push eax
    mov eax, [eax]
    call [eax].IPicture.Render
    test eax, eax
    jns @f;.IF SIGN?
        ; the call failed!
        push eax
        ; do some clean up first
        invoke ReleaseDC,ebx,compDC
        invoke DeleteDC, tempDC
        invoke DeleteObject, tempBitmap
        ; need to parse out the return fail value
seterror:call SetLastError
error:  xor eax,eax
        jmp exit
@@:    ;.ENDIF

    ; we now have the bitmap blitted, let's get it off the dc and clean up.
    ; we're not going to check for errors, cause we did our importaint thing
    ; and if these fail now, other things will fall apart anyway

    invoke ReleaseDC,ebx,compDC
    invoke SelectObject, tempDC, OldBitmap
    invoke DeleteDC, tempDC
   
    mov eax, tempBitmap     ; the bitmap handle is the return value
exit:    ret                     ; we're all done

BitmapFromPicture ENDP
.data
wTitle db "SEX-Tamagochi",0
CursorFile db "Images\heart.cur",0
btnClass db 'BUTTON',0
lpText db 'X',0
ClickMouse dd ?
handler dd a1,a2,a3,a4,a5,a0
hBmp dd ?
Cpt     dd 1
WScreen dd ?    
HScreen dd ?
WinX dd ?
WinY dd ?
x1Reg   dd ?
y1Reg   dd ?
x2Reg   dd ?
y2Reg   dd ?
hWnd dd ?
WinW dd 247,535+5,396+5,326+5,335+5,600+5
WinH dd 295,268+25,208+25,396+25,236+25,244+25
szImage db "IMAGE",0
IID_IPicture dd 07BF80980h,101ABF32h,0AA00BB8Bh,0AB0C3000h
Txt0 db 'oh! My Dear, click me!',0
Txt1 db 'hmmm! again, again...',0
Txt2 db "aaah! it's too much....",0
Txt3 db "iiih! You roast my circuits!...",0
Txt4 db "Stop Programmer, WORK!",0
Txt5 db "GoodBye My Dear...",0
handler2 dd Txt0,Txt1,Txt2,Txt3,Txt4,Txt5
rectTxt RECT <16,0,200,85>
end start
rsrc.rc#define ID_JPG1 1
#define ID_JPG2 2
#define ID_JPG3 3
#define ID_JPG4 4
#define ID_JPG5 5
#define ID_JPG6 6

ID_JPG1  IMAGE  "Images\\1.jpg"
ID_JPG2  IMAGE  "Images\\2.jpg"
ID_JPG3  IMAGE  "Images\\3.jpg"
ID_JPG4  IMAGE  "Images\\4.jpg"
ID_JPG5  IMAGE  "Images\\5.jpg"
ID_JPG6  IMAGE  "Images\\6.jpg"

Mikl__

And I tried... 14 downloaded and there are no questions...

six_L

Say you, Say me, Say the codes together for ever.

Mikl__


Siekmanski

Creative coders use backward thinking techniques as a strategy.

Mikl__


qWord

The code does break the WinABI. Also, you can't make any assumptions about the register content inside API callbacks (e.g. that EBX is still zero when WndProc is called).

regards
MREAL macros - when you need floating point arithmetic while assembling!

Mikl__

Quoteyou can't make any assumptions about the register content inside API callbacks
Hi, qWord!
Should not be treated with the same yardstick to all applications. The first line of the program after the label "start" is command "xor ebx,ebx". You can put in the EBX-register of any other value, then using debbagera sure that this value will be retained inside API callbacks. This technique can not be used when writing drivers, but for writing gui- and console- applications zeroing EBX-register is well suited.

regards

jj2007

Quote from: Mikl__ on December 22, 2015, 12:55:36 PMYou can put in the EBX-register of any other value, then using debbagera sure that this value will be retained inside API callbacks.

Even if this was the case (it isn't), that would be an undocumented feature.
A quick test on Win7-64 shows that on every entry to WndProc,
ebx = 0  ; lucky you, that was exactly what you needed :biggrin:
esi = 4010FBh
edi= 0

Of course, every Windows version can show a different behaviour - this is what they call "undocumented feature". For example, in the past I relied on Windows being nice to my xmm regs - they seemed magically protected. Then I wrote 32-bit applications on a 64-bit OS and bang!, they got merciless trashed by the OS. Relying on such empirically observed behaviour is a dangerously bad programming practice. MSDN tells you what is allowed and what isn't, and nobody else.

Mikl__


qWord

Not sure if you realized what is the point:
- the WndProc must preserve EBX, ESI, EDI and EBP due to the calling convention stdcall.
- the content of the registers ESI, EDI, EBX, EBP, EAX, EDX and ECX is undefined when the WndProc is called.
MREAL macros - when you need floating point arithmetic while assembling!

Mikl__

#11
Quote from: Grand InquisitorNot sure if you realized what is the point:
- the WndProc must preserve EBX, ESI, EDI and EBP due to the calling convention stdcall.
- the content of the registers ESI, EDI, EBX, EBP, EAX, EDX and ECX is undefined when the WndProc is called.

avcaballero

Quote from: René DescartesI would give everything I know by the half of what I don't know
Any reference to this info? Maybe only affect adversely to the program running in some cases? Many times don't seem to affect

Thank you

hutch--

 :biggrin:

I still find humour in folks who think they can second guess the Intel ABI. I am not sure what they are supposed to be gaining from living dangerously and writing code that risks going BANG on another OS version. Write you code in full compliance with the Intel ABI or when you least expect it, it will jump up and bite you (not BYTE you) and the OS will say nasty things about your code and it will be right. Do it the right way the first time and you can expect it to run on anything from Win95 OEM to Win12 Universe.  :P

Mikl__

Hi, hutch--!
I not understand well, but you were talking about me? I do not pretend to create a monumental code, but the trick of zeroing ebx-register worked in 32-bit Win 95/98/XP and continues to work in 64-bit Win7 without risks going BANG on another OS version.
P.S. it is strange that in Examples for Win64 Iczelion tutorial is no one outraged