News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests
NB: Posting URL's See here: Posted URL Change

Main Menu

ML errors

Started by tda0626, July 12, 2024, 08:11:40 AM

Previous topic - Next topic

tda0626

I am getting these errors when I try to assemble the code:

attribute roller.asm(63) : error A2088: END directive required at end of file
attribute roller.asm(63) : fatal error A1010: unmatched block nesting : WinMain

Everything looks correct in the code with end statements so not sure why it is doing it since most of it was copied from a previous working program. Source is attached.

Also, please look at my WM_Paint code to see if everything looks ok there too.Thanks!

Tim

fearless

WinMain isn't properly defined as a procedure, as it has no ret and ENDP

WinMain proc hinstance:HINSTANCE, hprevinstance:HINSTANCE, szCmdLine:LPSTR, CmdShow:DWORD

; ... some code

   ret
WinMain endp


Also there is no WndProc procedure either, so no WM_PAINT message to even look at.

And no end statement at the end of the file pointing to the entry, like:

END start

zedd151

Is your source code truncated somehow, it seems incomplete???

If not, try...
.386

option    casemap:none

include \masm32\include\masm32rt.inc

includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\gdi32.lib

WinMain proto :DWORD,:DWORD,:DWORD,:DWORD

.data
    szAppName db "Die Roller",0
    hinst HINSTANCE ?
    reg_failed db "Registration failed",0
    win_caption db "Die Roller",0
    commandline    LPSTR ?
   


.code

start:
    invoke GetModuleHandle,0
    mov hinst, eax
   
    invoke GetCommandLine
    mov commandline, eax
   
    push SW_SHOWDEFAULT
    push commandline
    push 0
    push hinst
    call WinMain

    invoke ExitProcess, eax
   
WinMain proc hinstance:HINSTANCE, hprevinstance:HINSTANCE, szCmdLine:LPSTR, CmdShow:DWORD
   
    local hwnd:HWND
    local msg:MSG
    local wndclass:WNDCLASSEXA
   
    mov wndclass.cbSize, sizeof wndclass
    mov wndclass.style, CS_HREDRAW or CS_VREDRAW
    mov wndclass.lpfnWndProc, offset WndProc
    mov wndclass.cbClsExtra, 0
    push 0
    pop wndclass.cbWndExtra
    push hinst
    pop wndclass.hInstance
    invoke LoadIcon, NULL, IDI_APPLICATION
    mov wndclass.hIcon, eax
    mov wndclass.hIconSm, eax
    invoke LoadCursor, NULL, IDC_ARROW
    mov wndclass.hCursor, eax
    invoke GetStockObject, WHITE_BRUSH
    mov wndclass.hbrBackground, eax
    mov wndclass.lpszMenuName, 0
    mov wndclass.lpszClassName, offset szAppName
   
    invoke RegisterClassExA, addr wndclass
    ; <---  possibly some missing code here???
    ret
Winmain endp

end start
I see fearless beat me to the draw...

I would think your source code had gotten corrupt somehow, there is no WndProc...
:azn:

NoCforMe

1. As others have pointed out, you have a PROC with no matching ENDP.
2. There's no END directive at the end of the code.
3. You need a message loop in the program.
4. You need a window procedure for your window (which is where your WM_PAINT handler would go).
5. You don't need any of this stuff, which is already in masm32rt.inc:
option    casemap:none
includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\gdi32.lib

6. Please don't do this (push-push-call):
    push SW_SHOWDEFAULT
    push commandline
    push 0
    push hinst
    call WinMain

Do this instead:
    INVOKE  WinMain, hInst, 0, commandLine, SW_SHOWDEFAULT

Seems like you meant to post more code than this but it somehow got left out ...
Assembly language programming should be fun. That's why I do it.

tda0626

Sorry, it was my mistake. I didn't save the new code so it had an earlier saved state.



Quote from: NoCforMe on July 12, 2024, 09:34:30 AM6. Please don't do this (push-push-call):
    push SW_SHOWDEFAULT
    push commandline
    push 0
    push hinst
    call WinMain




Yea that really chaps you ass doesn't it? JK  :joking: Yea the pushes were in there because I was just copying and pasting from an older working window program I have. I will correct it once I get it how I want it.

tda0626

Weird, Defender notifies me that my executable is suspect and scans it before it runs. I wonder if it doesn't like my random number code?

zedd151

Quote from: tda0626 on July 12, 2024, 10:16:32 AMWeird, Defender notifies me that my executable is suspect and scans it before it runs. I wonder if it doesn't like my random number code?
So does the correct and full version of your code assemble and link? Could you post the updated code?
:azn:

tda0626

Quote from: zedd151 on July 12, 2024, 10:27:30 AM
Quote from: tda0626 on July 12, 2024, 10:16:32 AMWeird, Defender notifies me that my executable is suspect and scans it before it runs. I wonder if it doesn't like my random number code?
So does the correct and full version of your code assemble and link? Could you post the updated code?

It does and appears to work so far as intended. I wanted to check my random number generator to see if it was working properly and then display the output. Next step is to use the RECT structure to help calculate the position of the text so I can print out my attributes and then have a roll of the dice display next to them. I will probably use TextOut to do that. Then  after that, capture key input to roll the dice again and update the window with new results. My source code is attached to this post. Please have a look at WM_PAINT section and let me know your thoughts. Any suggestions would be appreciated.

zedd151

I'll look at it when I'm back at my computah.
:azn:

NoCforMe

Quote from: tda0626 on July 12, 2024, 10:43:59 AMPlease have a look at WM_PAINT section and let me know your thoughts.

Looks OK to me, except for one thing:
You should use GetClientRect(), not GetWindowRect(). The latter gives you screen coordinates when what you need are window coords., that is, relative to your window (0,0).

You can count on GetClientRect() returning zero for both "left" and "top" members of RECT.
Assembly language programming should be fun. That's why I do it.

tda0626

Quote from: NoCforMe on July 12, 2024, 12:00:46 PM
Quote from: tda0626 on July 12, 2024, 10:43:59 AMPlease have a look at WM_PAINT section and let me know your thoughts.

Looks OK to me, except for one thing:
You should use GetClientRect(), not GetWindowRect(). The latter gives you screen coordinates when what you need are window coords., that is, relative to your window (0,0).

You can count on GetClientRect() returning zero for both "left" and "top" members of RECT.


Thanks that is perfect. Now when I maximize and minimize the window it prints out another random number. What is the best way to to prevent that from happening? Write separate procedure for all the die rolls then on a certain keypress call that procedure again for new rolls or something like that?

Tim

NoCforMe

Quote from: tda0626 on July 12, 2024, 10:43:59 AMThen  after that, capture key input to roll the dice again and update the window with new results.

Keep in mind that this ain't DOS and you can't use INT 16 to capture keystrokes.
You can create an edit control and use that for user input. Or if all you need is a signal that the user clicked something, use a button control.
Assembly language programming should be fun. That's why I do it.

NoCforMe

Quote from: tda0626 on July 12, 2024, 12:15:21 PMNow when I maximize and minimize the window it prints out another random number. What is the best way to to prevent that from happening?

What's probably happening is that when you change the size of the window, it "invalidates" the window, which triggers your WM_PAINT handler.

You could set up a flag in the program that controls this. Make the flag a global (a BYTE-sized variable will work fine). If you want to disable updates until the user does something, set the flag to FALSE, then check it in your WM_PAINT handler. If the flag is false, then bypass the code that prints out another random #. Set it to TRUE when you want a new random # to display.

Important: Make sure you still call BeginPaint() and EndPaint() in your WM_PAINT handler, even if you don't change the display. Otherwise the WM_PAINT messages will pile up and bad things will happen. The sequence of those two calls removes the paint request from the queue.
Assembly language programming should be fun. That's why I do it.

zedd151

First, I put the rand routines in WM_CREATE for the initial random number.
Then I also put it in WM_CHAR using the space bar to initiate next random number(s)... all of that plus commented out the random routine from WM_PAINT.

I did not change the positioning of the text, I'll leave it for you.  :biggrin:
.386

option    casemap:none

include \masm32\include\masm32rt.inc

includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\gdi32.lib

WinMain proto :DWORD,:DWORD,:DWORD,:DWORD
RNDNumber proto :dword, :DWORD
WndProc proto :DWORD,:DWORD,:DWORD,:DWORD


.data
    szAppName db "Attribute Roller",0
    hinst HINSTANCE ?
    reg_failed db "Registration failed",0
    win_caption db "Attribute Roller",0
    commandline    LPSTR ?
    mainseed    dd    0
    numbtoASCII    db    3 dup (0)
    rand        dd    0
   
Attributes STRUCT
    strength        db    "STR:",0
    dexterity        db    "DEX:",0
    constitution    db    "CON:",0
    intelligence    db    "INT:",0
    wisdom            db    "WIS:",0
    charisma        db    "CHR:",0
Attributes ENDS


.code

start:
    invoke GetModuleHandle,0
    mov hinst, eax
   
    invoke GetCommandLine
    mov commandline, eax
   
    push SW_SHOWDEFAULT
    push commandline
    push 0
    push hinst
    call WinMain

    invoke ExitProcess, eax
   
    WinMain proc hinstance:HINSTANCE, hprevinstance:HINSTANCE, szCmdLine:LPSTR, CmdShow:DWORD
   
    local hwnd:HWND
    local msg:MSG
    local wndclass:WNDCLASSEXA

   
    mov wndclass.cbSize, sizeof wndclass
    mov wndclass.style, CS_HREDRAW or CS_VREDRAW
    mov wndclass.lpfnWndProc, offset WndProc
    mov wndclass.cbClsExtra, 0
    push 0
    pop wndclass.cbWndExtra
    push hinst
    pop wndclass.hInstance
    invoke LoadIcon, NULL, IDI_APPLICATION
    mov wndclass.hIcon, eax
    mov wndclass.hIconSm, eax
    invoke LoadCursor, NULL, IDC_ARROW
    mov wndclass.hCursor, eax
    invoke GetStockObject, WHITE_BRUSH
    mov wndclass.hbrBackground, eax
    mov wndclass.lpszMenuName, 0
    mov wndclass.lpszClassName, offset szAppName
   
    invoke RegisterClassExA, addr wndclass
   
    .if eax==0
        invoke MessageBoxA, NULL, offset reg_failed, offset szAppName, MB_ICONERROR
        ret
    .endif
   
    invoke CreateWindowExA,\
    WS_EX_LEFT,\
    offset szAppName,\
    offset win_caption,\
    WS_OVERLAPPEDWINDOW ,\
    CW_USEDEFAULT,\
    CW_USEDEFAULT,\
    CW_USEDEFAULT,\
    CW_USEDEFAULT,\
    0,\
    NULL,\
    hinstance,\
    NULL
   
    mov hwnd, eax
   
    invoke ShowWindow, hwnd, SW_SHOWNORMAL
    invoke UpdateWindow, hwnd
   
   
   
messageLoop:
    invoke GetMessage, addr msg, 0, 0, 0
    cmp eax, 0
    je endLoop
    invoke TranslateMessage, addr msg
    invoke DispatchMessage, addr msg
    jmp messageLoop
   
endLoop:
    mov eax, msg.wParam
    ret
WinMain endp


WndProc proc hWnd:HWND, message:UINT, wParam:WPARAM, lParam:LPARAM   
   
   
    local hdc:HDC
    local ps:PAINTSTRUCT
    local rc:RECT
    local ft:FILETIME
   
   
    SWITCH message
   
   
    CASE WM_CHAR
          switch wParam
          case VK_SPACE ; <-- spacebar
        invoke GetSystemTimeAsFileTime, addr ft
        mov eax, ft.dwLowDateTime
        mov mainseed, eax
        invoke RNDNumber, 18, mainseed
       
        ;--------------------------------------
       
        ;-Convert to ASCII and then display result-
       
        mov eax, rand
        inc eax            ; Only want values from 1-18
        xor edx, edx
        mov ecx, 10
        div ecx
        add edx, 48
        add eax, 48
        mov numbtoASCII, al
        mov numbtoASCII+1, dl
            invoke InvalidateRect, hWnd, 0, TRUE
          endsw
     
    CASE WM_CREATE
        invoke GetSystemTimeAsFileTime, addr ft
        mov eax, ft.dwLowDateTime
        mov mainseed, eax
        invoke RNDNumber, 18, mainseed
       
        ;--------------------------------------
       
        ;-Convert to ASCII and then display result-
       
        mov eax, rand
        inc eax            ; Only want values from 1-18
        xor edx, edx
        mov ecx, 10
        div ecx
        add edx, 48
        add eax, 48
        mov numbtoASCII, al
        mov numbtoASCII+1, dl
    CASE WM_PAINT
   
        invoke BeginPaint, hWnd, addr ps
        mov hdc, eax
        invoke GetWindowRect, hWnd, addr rc
       
        ;-Seed Random Number Generator---------
       
 ;        invoke GetSystemTimeAsFileTime, addr ft
 ;        mov eax, ft.dwLowDateTime
 ;        mov mainseed, eax
 ;        invoke RNDNumber, 18, mainseed
 ;       
 ;        ;--------------------------------------
 ;       
 ;        ;-Convert to ASCII and then display result-
 ;       
 ;        mov eax, rand
 ;        inc eax            ; Only want values from 1-18
 ;        xor edx, edx
 ;        mov ecx, 10
 ;        div ecx
 ;        add edx, 48
 ;        add eax, 48
 ;        mov numbtoASCII, al
 ;        mov numbtoASCII+1, dl
        invoke DrawText,hdc,offset numbtoASCII,-1,addr rc,DT_CENTER or DT_VCENTER
       
        ;------------------------------------------
       
       
        invoke EndPaint, hWnd, addr ps
       
        ret
       
       
       
   
    CASE WM_DESTROY
   
        invoke PostQuitMessage, 0
        ret
       
    ENDSW
   
        invoke DefWindowProc, hWnd, message, wParam, lParam
       
        ret

WndProc endp

RNDNumber proc modulus:dword, seed:dword
       
        mov eax, seed        ; seed =  seed XOR ( seed << 1 )
        shl eax, 1
        xor eax, seed
        mov seed,  eax
       
        mov eax, seed        ; seed = seed XOR ( seed >> 5 )
        shr eax, 5
        xor eax, seed
        mov seed, eax
       
        mov eax, seed        ; mainseed =  seed XOR ( seed << 6 )
        shl eax, 6
        xor eax, seed
        mov seed, eax    ; use mainseed to seed the next call to RNDNumber
       
        mov eax, seed        ; mainseed =  seed XOR ( seed << 31 )
        shl eax, 31
        xor eax, seed
        mov mainseed, eax    ; use mainseed to seed the next call to RNDNumber
       
        xor edx, edx
        div modulus
        mov rand, edx        ; Store remainder

        ret
   
RNDNumber endp



   

END start
There are most likely other ways to do the same. I just offer one example here.  :tongue:  It is not perfect, but should give you some ideas.

Sorry for the long delay, Tim. Real life interferes and I had forgotten about this til just now.
Btw, no ml errors here nor any Defender issues (I'm running Windows 7).  :cool:
:azn:

NoCforMe

Looks OK.
You can get rid of the following:
; These are already in masm32rt.inc:
includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\gdi32.lib

; Totally unnecessary: CreateWindowEx() will take care of this:
    invoke ShowWindow, hwnd, SW_SHOWNORMAL
    invoke UpdateWindow, hwnd

; but add this style when you create the window:
    WS_OVERLAPPEDWINDOW or WS_VISIBLE,\
Assembly language programming should be fun. That's why I do it.