News:

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

Main Menu

newb question - creating buttons/correct const syntax

Started by Anaryl, February 22, 2016, 05:56:47 AM

Previous topic - Next topic

Anaryl

Hallo there! Forgive my newb question -

So I'm working my way through a random tutorial on assembly that I found on my harddrive that I must've picked up in a dump somewhere. Unfortuantely the last chapter seems to have been written just before the writer gave up on the tutorial altogether as it becomes rather sparse on details.

The specification for the code being thus:

QuoteOnce we make a window, we'll want to put some buttons and textboxes on it.
Fortunately, this is easy! The syntax is very similar to creating a window, except we
won't have to call RegisterClassEx because our class will be predefined for us.

I have become stuck on a part that states:


QuoteUnder the .data section, you will need to add some variables. Define EditClassName as
"edit" and ButtonClassName as "button". Also, you need to have EditID and
ButtonID defined to be constants. It doesn't matter what they are as long as they don't
have the same ID as any other control. Also, you will need uninitialized variables, hEdit
and hButton, which are of type HWND. And lastly, ButtonText needs to be a string,
which will be displayed on the button.

.elseif uMsg == WM_CREATE
invoke CreateWindowEx, NULL, addr ButtonClassName, addr ButtonText, WS_CHILD
or WS_VISIBLE or BS_DEFPUSHBUTTON, 10, 50, 80, 30, hWnd, ButtonID, hInstance, NULL
mov hButton, eax
invoke CreateWindowEx, WS_EX_CLIENTEDGE, addr EditClassName, NULL, WS_CHILD
or WS_VISIBLE, 10, 10, 100,


To which no example code has been provided for the example on how exactly this is implemented. I've done a bit of searching around the place but what is expected of me here is not entirely clear. Usually I would keep googling about but alas my connection has been shaped and after a few hours I seem to not be getting very far, and I have an ugly habit of not asking for help.



My code thus far (mostly provided by the text itself)

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

WinMain proto :DWORD, :DWORD, :DWORD, :DWORD ;function prototype eg c++ func decl

.data
        ClassName   db "WinClass", 0
        AppName     db "Simple Window", 0 ; string variable declaration
        EditClassName db "edit", 0
        ButtonClassName db "button", 0

.data?

        hInstance HINSTANCE ? ;hinstance stores the handle to the instance of the module to be associated with the window. We will need to pass it into the createwindow funtion later
        hEdit HWND ?
        hButton HWND ?
        ButtonText string

const.
        ButtonID   
        EditID

.code
start:

        invoke GetModuleHandle, NULL
        mov hInstance, eax
        invoke WinMain, hInstance, NULL, NULL, 0
        invoke ExitProcess, eax ; get the modulehandle and stores into hInstance then calls WinMain and exits

WinMain proc hInst:HINSTANCE, hPrevInst:HINSTANCE, CmdLine:LPSTR, CmdShow:DWORD
        local wc:WNDCLASSEX
        local msg:MSG
        local hwnd:HWND ; beginning of our winmian func we declare 3 local var we, msg and hwnd. wc stores the window class, template for windows, msg stores the messages that the msg loop restrieves, hwnd stores the handle to the window
        mov wc.cbSize, SIZEOF WNDCLASSEX
        mov wc.style, CS_HREDRAW or CS_VREDRAW
        mov wc.lpfnWndProc, offset WndProc
        mov wc.cbClsExtra,NULL
        mov wc.cbWndExtra, NULL
        push hInstance
        pop wc.hInstance
        mov wc.hbrBackground, COLOR_WINDOW+1
        mov wc.lpszMenuName, NULL
        mov wc.lpszClassName, offset ClassName
        invoke LoadIcon, NULL, IDI_APPLICATION
        mov wc.hIcon, eax
        mov wc.hIconSm, eax
        invoke LoadCursor, NULL, IDC_ARROW
        mov wc.hCursor, eax
        invoke RegisterClassEx, addr wc ; All this does is fill the wc struct we decl ealier registerClassex is then called taking wc as the param.
        invoke CreateWindowEx, 0, addr ClassName, addr AppName, WS_OVERLAPPEDWINDOW or WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInst, NULL
        mov hwnd, eax ; create the createWindowEx function that actually creates the window. params are passed in to specific how to make the win, handle is returned and stored in hwnd

.while TRUE
    invoke GetMessage, addr msg, NULL, 0, 0
    .break .if (!eax)
    invoke TranslateMessage, addr msg
    invoke DispatchMessage, addr msg
    .endw ; while loop which is the message loop when an input occurs windows translates the the event into a message and passes the mesage in the progs msg queue. getmessage retrieves the msg and stores them in msg translatemsg changes key message into char msgs dispatch sends the msg to wndProc where it is processed
    mov eax, msg.wParam
    ret

WinMain endp
;the return value is stored into msg.wParam and WinMain is ended

WndProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
    .if uMsg == WM_DESTROY
        invoke PostQuitMessage, 0
        .else
            invoke DefWindowProc, hWnd, uMsg, wParam, lParam
            ret
            .endif
            xor eax, eax
            ret
       .elseif uMsg == WM_CREATE
               invoke CreateWindowEx, NULL, addr ButtonClassName, addr ButtonText, WS_CHILD or WS_VISIBLE or BS_DEFPUSHBUTTON, 10, 50, 80, 30, hWnd, ButtonID, hInstance, NULL
               mov hButton, eax
               invoke CreateWindowEx, WS_EX_CLIENTEDGE, addr EditClassName, NULL, WS_CHILD or WS_VISIBLE, 10, 10, 100, 20, hWnd, EditId, hInstance, NULL
               mov, hEdit, eax
WndProc endp

;WndProc function is where messages are processed the only message that must be processed is WM_DESTROY which calls PostQuitMessage to quit. If there are other events you want porcessed you would add them here Common message to process are WM_CREATE when window is created
; WM_PAINT when the window needs repainting and WM_CLOSE when the window is closed. anything that isnt'handled is passed on to the defWindowProc function which it the dfault handler

end start


This generates (obviously) :
Quote
Assembling: A:\masm32\win2.asm

***********
ASCII build
***********

A:\masm32\win2.asm(72) : fatal error A1011: directive must be in control block



I'm sorry this is probably quite the newb question. I've tried glancing through the intel software manuals but they are dense tomes, and I'm going to try looking for a few other tutorials presently - but alas - I also have a nasty habit of not finishing projects that I start and since this is the last problem it would be nice to simply knock this one out of the way *then* move to other tutorials.

Anyways any help here would be greatly appreciated.

GoneFishing

Read .if .else .elseif .endif thread .
You forgot to add .endif statement before WndProc endp .

Anaryl

I'll try it now, but is that it? I thought I'm not declaring const. correctly.

QuoteA:\masm32\win2.asm(23) : error A2008: syntax error : ButtonText
A:\masm32\win2.asm(25) : error A2008: syntax error : .
A:\masm32\win2.asm(26) : error A2008: syntax error : ButtonID
A:\masm32\win2.asm(27) : error A2008: syntax error : EditID
A:\masm32\win2.asm(81) : fatal error A1011: directive must be in control block

Sorry, yeah normally I'm more rigorous with researching but since my connection has been shaped (damn excess dat charges on my mobile) I can't run more than one tab without losing connection to another.

Anyways the part of the tutorial I'm having trouble parsing is this section

QuoteUnder the .data section, you will need to add some variables. Define EditClassName as
"edit" and ButtonClassName as "button". Also, you need to have EditID and
ButtonID defined to be constants. It doesn't matter what they are as long as they don't
have the same ID as any other control. Also, you will need uninitialized variables, hEdit
and hButton, which are of type HWND. And lastly, ButtonText needs to be a string,
which will be displayed on the button.

Which I believe is this section of the code

Quote.data
        ClassName   db "WinClass", 0
        AppName     db "Simple Window", 0 ; string variable declaration
        EditClassName db "edit", 0
        ButtonClassName db "button", 0

.data?

        hInstance HINSTANCE ? ;hinstance stores the handle to the instance of the module to be associated with the window. We will need to pass it into the createwindow funtion later
        hEdit HWND ?
        hButton HWND ?
        ButtonText string

const.
        ButtonID   
        EditID

.code

So when the text says define the class names that seems straightforward enough but then when it says define the EditID and ButtonID to be constants I know where to write that code, but the syntax I'm not entirely certain of and then when it says buttonText needs to be a string, I become a bit lost entirely.

GoneFishing

It's the first error . Fix it and you'll get the next one.

Now let's fix this error
QuoteA:\masm32\win2.asm(81) : fatal error A1011: directive must be in control block

Line 81 :
   .elseif uMsg == WM_CREATE
Did you read the thread I posted a link to ?
.elseifs go first, followed by .else (if needed)

BTW Your first tutorial is too complex

Anaryl

Sorry was updating my post with the new information, accidentally posted before I was finished. :)

GoneFishing

Look in masm32\examples folder. Lots of material there
You'd better to start from simple things like console application

Anaryl

Quote from: GoneFishing on February 22, 2016, 07:01:10 AM
It's the first error . Fix it and you'll get the next one.

Now let's fix this error
QuoteA:\masm32\win2.asm(81) : fatal error A1011: directive must be in control block

Line 81 :
   .elseif uMsg == WM_CREATE
Did you read the thread I posted a link to ?
.elseifs go first, followed by .else (if needed)

BTW Your first tutorial is too complex

Ah no I haven't looked at it just yet - I was on a webchat to my ISP trying to get some bandwidth reprieve (an whole other amusing story in of itself, but let's just say my phones trying to do an OTA update on dialup speeds); so I was unsuccessfully trying to multitask.

In regards to the tutorial well there's five chapters, and this is the last exercise, so technically not the first example.

But I was looking on the main masm32 page which I had already opened and cached and saw the formatting presented as thus

QuoteBlock structure conditional testing is routine in MASM with an efficient and clear notation that is useful in all but the most demanding algorithms where direct mnemonic code can bypass unrequired structure for maximum performance.

Quote.if eax == 1
      ; do something
    .elseif eax == 2
      ; do something else
    .else
      ; otherwise do this
    .endif

So I tried shifting the else block and it screamed at me more so than before

QuoteA:\masm32\win2.asm(23) : error A2008: syntax error : ButtonText
A:\masm32\win2.asm(25) : error A2008: syntax error : .
A:\masm32\win2.asm(26) : error A2008: syntax error : ButtonID
A:\masm32\win2.asm(27) : error A2008: syntax error : EditID
A:\masm32\win2.asm(77) : error A2006: undefined symbol : ButtonID
A:\masm32\win2.asm(77) : error A2114: INVOKE argument type mismatch : argument : 10
A:\masm32\win2.asm(77) : error A2006: undefined symbol : ButtonText
A:\masm32\win2.asm(77) : error A2114: INVOKE argument type mismatch : argument : 3
A:\masm32\win2.asm(79) : error A2006: undefined symbol : EditId
A:\masm32\win2.asm(79) : error A2114: INVOKE argument type mismatch : argument : 10
A:\masm32\win2.asm(80) : error A2008: syntax error : ,
A:\masm32\win2.asm(88) : fatal error A1011: directive must be in control block

rest assured (as my bandwidth is restored shortly) I will look over that thread shortly - I'm sure I can figure out the syntax issues on the endif issue. I've just got to go ahead and restart my router, so I'll go do that shortly - but my main issue is figuring out the const syntax rather than the loop syntax (although historically given how much trouble loops have given I'd be unsurprised if I need help there too). Hopefully my bandwidth woes will make it a bit easier to view some of these resources.

To give you an idea of where I was at before I was quite able to get this code to run successfully which is the code from an earlier example that the text is now asking me to modify
.386
.model flat, stdcall
option casemap :none
include \masm32\include\windows.inc
include \masm32\include\user32.inc
include \masm32\include\kernel32.inc
includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib

WinMain proto :DWORD, :DWORD, :DWORD, :DWORD ;function prototype eg c++ func decl

.data
        ClassName   db "WinClass", 0
        AppName     db "Simple Window", 0 ; string variable declaration

.data?

        hInstance HINSTANCE ? ;hinstance stores the handle to the instance of the module to be associated with the window. We will need to pass it into the createwindow funtion later

.code
start:

        invoke GetModuleHandle, NULL
        mov hInstance, eax
        invoke WinMain, hInstance, NULL, NULL, 0
        invoke ExitProcess, eax ; get the modulehandle and stores into hInstance then calls WinMain and exits

WinMain proc hInst:HINSTANCE, hPrevInst:HINSTANCE, CmdLine:LPSTR, CmdShow:DWORD
        local wc:WNDCLASSEX
        local msg:MSG
        local hwnd:HWND ; beginning of our winmian func we declare 3 local var we, msg and hwnd. wc stores the window class, template for windows, msg stores the messages that the msg loop restrieves, hwnd stores the handle to the window
        mov wc.cbSize, SIZEOF WNDCLASSEX
        mov wc.style, CS_HREDRAW or CS_VREDRAW
        mov wc.lpfnWndProc, offset WndProc
        mov wc.cbClsExtra,NULL
        mov wc.cbWndExtra, NULL
        push hInstance
        pop wc.hInstance
        mov wc.hbrBackground, COLOR_WINDOW+1
        mov wc.lpszMenuName, NULL
        mov wc.lpszClassName, offset ClassName
        invoke LoadIcon, NULL, IDI_APPLICATION
        mov wc.hIcon, eax
        mov wc.hIconSm, eax
        invoke LoadCursor, NULL, IDC_ARROW
        mov wc.hCursor, eax
        invoke RegisterClassEx, addr wc ; All this does is fill the wc struct we decl ealier registerClassex is then called taking wc as the param.
        invoke CreateWindowEx, 0, addr ClassName, addr AppName, WS_OVERLAPPEDWINDOW or WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInst, NULL
        mov hwnd, eax ; create the createWindowEx function that actually creates the window. params are passed in to specific how to make the win, handle is returned and stored in hwnd

.while TRUE
    invoke GetMessage, addr msg, NULL, 0, 0
    .break .if (!eax)
    invoke TranslateMessage, addr msg
    invoke DispatchMessage, addr msg
    .endw ; while loop which is the message loop when an input occurs windows translates the the event into a message and passes the mesage in the progs msg queue. getmessage retrieves the msg and stores them in msg translatemsg changes key message into char msgs dispatch sends the msg to wndProc where it is processed
    mov eax, msg.wParam
    ret

WinMain endp
;the return value is stored into msg.wParam and WinMain is ended

WndProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
    .if uMsg == WM_DESTROY
        invoke PostQuitMessage, 0
        .else
            invoke DefWindowProc, hWnd, uMsg, wParam, lParam
            ret
            .endif
            xor eax, eax
            ret
WndProc endp

;WndProc function is where messages are processed the only message that must be processed is WM_DESTROY which calls PostQuitMessage to quit. If there are other events you want porcessed you would add them here Common message to process are WM_CREATE when window is created
; WM_PAINT when the window needs repainting and WM_CLOSE when the window is closed. anything that isnt'handled is passed on to the defWindowProc function which it the dfault handler

end start

Anaryl

Sorry to double post. Yeah I had a look over the thread it didn't seem to indicate that much more than what i had read elsewhere so I'm not entirely understanding the control block syntax  I've got a few ideas on where to go with that though. [edit] fixed it [/edit]

Any help on the const. syntax? This is where I'm at now

QuoteA:\masm32\win2.asm(23) : error A2008: syntax error : ButtonText
A:\masm32\win2.asm(25) : error A2008: syntax error : .
A:\masm32\win2.asm(26) : error A2008: syntax error : ButtonID
A:\masm32\win2.asm(27) : error A2008: syntax error : EditID
A:\masm32\win2.asm(76) : error A2006: undefined symbol : ButtonID
A:\masm32\win2.asm(76) : error A2114: INVOKE argument type mismatch : argument : 10
A:\masm32\win2.asm(76) : error A2006: undefined symbol : ButtonText
A:\masm32\win2.asm(76) : error A2114: INVOKE argument type mismatch : argument : 3
A:\masm32\win2.asm(78) : error A2006: undefined symbol : EditId
A:\masm32\win2.asm(78) : error A2114: INVOKE argument type mismatch : argument : 10

jj2007


fearless

ButtonText string

should be in your .data section and defined as a string like you did with your EditClassName and ButtonClassName variables:

.data
ButtonText db "This is a button, press me.",0

Anaryl

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

WinMain proto :DWORD, :DWORD, :DWORD, :DWORD ;function prototype eg c++ func decl

.data
        ClassName   db "WinClass", 0
        AppName     db "Simple Window", 0 ; string variable declaration
        EditClassName db "edit", 0
        ButtonClassName db "button", 0
        ButtonText db "I am a button, press me!", 0

.data?

        hInstance HINSTANCE ? ;hinstance stores the handle to the instance of the module to be associated with the window. We will need to pass it into the createwindow funtion later
        hEdit HWND ?
        hButton HWND ?
       

.const
        ButtonID equ 1   
        EditId equ 2

.code
start:

        invoke GetModuleHandle, NULL
        mov hInstance, eax
        invoke WinMain, hInstance, NULL, NULL, 0
        invoke ExitProcess, eax ; get the modulehandle and stores into hInstance then calls WinMain and exits

WinMain proc hInst:HINSTANCE, hPrevInst:HINSTANCE, CmdLine:LPSTR, CmdShow:DWORD
        local wc:WNDCLASSEX
        local msg:MSG
        local hwnd:HWND ; beginning of our winmian func we declare 3 local var we, msg and hwnd. wc stores the window class, template for windows, msg stores the messages that the msg loop restrieves, hwnd stores the handle to the window
        mov wc.cbSize, SIZEOF WNDCLASSEX
        mov wc.style, CS_HREDRAW or CS_VREDRAW
        mov wc.lpfnWndProc, offset WndProc
        mov wc.cbClsExtra,NULL
        mov wc.cbWndExtra, NULL
        push hInstance
        pop wc.hInstance
        mov wc.hbrBackground, COLOR_WINDOW+1
        mov wc.lpszMenuName, NULL
        mov wc.lpszClassName, offset ClassName
        invoke LoadIcon, NULL, IDI_APPLICATION
        mov wc.hIcon, eax
        mov wc.hIconSm, eax
        invoke LoadCursor, NULL, IDC_ARROW
        mov wc.hCursor, eax
        invoke RegisterClassEx, addr wc ; All this does is fill the wc struct we decl ealier registerClassex is then called taking wc as the param.
        invoke CreateWindowEx, 0, addr ClassName, addr AppName, WS_OVERLAPPEDWINDOW or WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInst, NULL
        mov hwnd, eax ; create the createWindowEx function that actually creates the window. params are passed in to specific how to make the win, handle is returned and stored in hwnd

.while TRUE
    invoke GetMessage, addr msg, NULL, 0, 0
    .break .if (!eax)
    invoke TranslateMessage, addr msg
    invoke DispatchMessage, addr msg
    .endw ; while loop which is the message loop when an input occurs windows translates the the event into a message and passes the mesage in the progs msg queue. getmessage retrieves the msg and stores them in msg translatemsg changes key message into char msgs dispatch sends the msg to wndProc where it is processed
    mov eax, msg.wParam
    ret

WinMain endp
;the return value is stored into msg.wParam and WinMain is ended

WndProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
    .if uMsg == WM_DESTROY
        invoke PostQuitMessage, 0
    .elseif uMsg == WM_CREATE
        invoke CreateWindowEx, NULL, addr ButtonClassName, addr ButtonText, WS_CHILD or WS_VISIBLE or BS_DEFPUSHBUTTON, 10, 50, 80, 30, hWnd, ButtonID, hInstance, NULL
         mov hButton, eax
         invoke CreateWindowEx, WS_EX_CLIENTEDGE, addr EditClassName, NULL, WS_CHILD or WS_VISIBLE, 10, 10, 100, 20, hWnd, EditId, hInstance, NULL
         mov hEdit, eax
    .elseif uMsg == WM_COMMAND
        mov eax, wParam
        .if ax == ButtonID
            shr eax, 16
            .if ax == BN_CLICKED
            ;code for button click
            .endif
        .endif
    .else
        invoke DefWindowProc, hWnd, uMsg, wParam, lParam
        ret
        xor eax, eax
        ret
       .endif
WndProc endp

;WndProc function is where messages are processed the only message that must be processed is WM_DESTROY which calls PostQuitMessage to quit. If there are other events you want porcessed you would add them here Common message to process are WM_CREATE when window is created
; WM_PAINT when the window needs repainting and WM_CLOSE when the window is closed. anything that isnt'handled is passed on to the defWindowProc function which it the dfault handler

end start


So I almost have it (and yes I should have checked those examples sooner! and thank you fearless I was wondering why the button text wasn't working.

But alas I'm getting some unexpected behaviour in that I know have a random textfield above the button that also causes the application to crash when I click on it. I'm wondering how I seem have managed to have let that slip in?

[edit] my guess is the hEdit HWND ? let's see what breaks when I take it out?
Quoteerror A2006: undefined symbol : hEdit
- not entirely unexpected.

jj2007

That code doesn't look very correct, where did you get it?

With these minor corrections, it runs, but ...
        invoke DefWindowProc, hWnd, uMsg, wParam, lParam
        ret
        ; xor eax, eax      ; this code
        ; ret                  ; never reached
    .endif
    ret
WndProc endp

Anaryl

To be honest I have no idea where I got it, it was a random .pdf in a bookdump I found whilst trying organise an old hard drive on my secondary rig - it's dated from 2003 and from what I can tell it looks like it was written as a university assignment. It's only 17 pages/5 chapters - and the last chapter which i've been having issues with seems to have been written in a hurry then abandoned. I've been going through the tutes at http://win32assembly.programminghorizon.com and they seem to be better laid out. The problem with the last exercise is that it wants me to edit a previous one (which I quoted earlier) but it isn't always clear what I need to take out or where the new code needs to go - which can be challenging. I dislike shrinking from a challenge though so am rather determined to make it work rather than simply give up - always a good learning experience.

When you say it runs, but ... ?

Ah yes, the program doesn't crash now and the textbox was supposed to be there in the first place (damn my sleepy brain). I suppose I can put in some code for textoutput. The tutorial ends quite abruptly with


QuotewParam contains information about the message. We should check it to see if it is the
button that sent the message, since we don't want to process the message of other
controls yet. shr is the shift right operator, which shifts wParam 16 bits to the right.
This is a useful method to get the high 16 bits of a 32-bit register so that they can be
easily accessed by ax.

.if ax == BN_CLICKED
            ;code for button click
            .endif
        .endif

QuoteSo now that we know the button has been clicked, we can do something about it.

But I think my sleepy mind is beginning to miss a few things that I could pick up if i was not on the verge of unconsciousness.

TouEnMasm


I prefer the explain of MSDN at your book.
https://msdn.microsoft.com/fr-fr/library/windows/desktop/ms647591(v=vs.85).aspx

mov eax,wparam
The hiword of wparam ( shift right 16 of eax) give the message  WM_....
The loword of wparam (and eax,0FFFFh) give the ID_ of the control (an arbitrary number you have defined)

The lparam give the handle of the control (given by the system)

Prefer to use the handle in lparam instead of the loword of wparam.

Fa is a musical note to play with CL

dedndave

if it's a button, and the notification code is BN_CLICKED, the high word will be 0
(BN_CLICKED EQU 0)

if it's a menu item click, the high word will also be 0

so, for those items. you can test the entire DWORD as a single value

    mov     eax,uMsg
    .if eax==WM_something
        ;
    .elseif eax==WM_COMMAND
        mov     eax,wParam
        .if eax==button_id_value
            ;do button code
        .elseif eax==menu_id_value
            ;do menu item code
        .endif
        xor     eax,eax              ;return 0

    .elseif eax==WM_something_else
        ;
    .else
        INVOKE  DefaultWindowProc......
    .endif
    ret