News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

I'm obviously doing something wrong.. but what?

Started by ekisner, August 28, 2009, 09:37:01 PM

Previous topic - Next topic

ekisner

When I compile and link, I don't get any errors.. running the program from command prompt causes it to drop to a blank line like the program is running, but absolutely nothing happens.  I'm obviously missing something small, or I've done something stupid (or both).  Or perhaps I've made a very large oversight.. I don't know :(

This is just a basic window program.. as I understand the code, it should do nothing but open a blank window.  Code is taken almost line for line from a tutorial - I replaced all of the invoke commands with call commands (pushing the parameters myself), but other than that it is line for line.

.386
.model flat,stdcall
option casemap:none

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

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

.data
    AppName     db          "AppName",0
    ClassName   db          "ClassName",0
    var         db          1
.data?
    hInstance   HINSTANCE   ?
    CommandLine LPSTR       ?

.code

start:
    push NULL
    call GetModuleHandle
    mov hInstance,eax

    call GetCommandLine
    mov CommandLine,eax

    push SW_SHOWDEFAULT
    push NULL
    push NULL
    lea eax,hInstance
    push eax
    call WinMain

    push NULL
    call ExitProcess

WinMain proc hInst:HINSTANCE,hPrevInst:HINSTANCE,CmdLine:LPSTR,CmdShow:DWORD
    LOCAL wc:WNDCLASSEX
    LOCAL msg:MSG
    LOCAL hwnd:HWND

    mov wc.cbSize,SIZEOF WNDCLASS
    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

    push IDI_APPLICATION
    push NULL
    call LoadIcon
    mov wc.hIcon,eax
    mov wc.hIconSm,eax

    push IDC_ARROW
    push NULL
    call LoadCursor
    mov wc.hCursor,eax

    lea eax,wc
    push eax
    call RegisterClassEx

    push NULL
    push hInst
    push NULL
    push NULL
    push CW_USEDEFAULT
    push CW_USEDEFAULT
    push CW_USEDEFAULT
    push CW_USEDEFAULT
    push WS_OVERLAPPEDWINDOW
    lea eax,AppName
    push eax
    lea eax,ClassName
    push eax
    push NULL
    call CreateWindowEx

    mov hwnd,eax
    push CmdShow
    push hwnd
    call ShowWindow
    push hwnd
    call UpdateWindow

    .WHILE TRUE
        push 0
        push 0
        push NULL
        push msg
        call GetMessage
;        .BREAK .IF(!eax)
        lea eax,msg
        push eax
        call TranslateMessage
        lea eax,msg
        push eax
        call DispatchMessage
    .ENDW
    mov eax,msg.wParam
    ret
WinMain endp

WndProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
    .IF uMsg==WM_DESTROY
        push NULL
        call PostQuitMessage
    .ELSE
        push lParam
        push wParam
        push uMsg
        push hWnd
        call DefWindowProc
        ret       
    .ENDIF
    xor eax,eax
    ret
WndProc endp

end start



I've tried replacing the "call" calls with "invoke" and setting the parameters the same as in the tutorial.. same effect.

Slugsnack

mov wc.cbSize,SIZEOF WNDCLASS

mov wc.cbSize, SIZEOF WNDCLASSEX

Tedd

To get it working..

    push SW_SHOWDEFAULT
    push NULL
    push NULL
;;lea gives you the address of a variable, not its value
;    lea eax,hInstance
mov eax,hInstance
    push eax
    call WinMain


;;you're calling RegisterClassEx, so you need to use the appropriate 'ex' structure
;;it's generally safer to use the size of the structure you're actually using (i.e. 'wc')
;    mov wc.cbSize,SIZEOF WNDCLASS
mov wc.cbSize,SIZEOF wc
    mov wc.style, CS_HREDRAW or CS_VREDRAW
    mov wc.lpfnWndProc, OFFSET WndProc
    mov wc.cbClsExtra, NULL
    mov wc.cbWndExtra, NULL


        push 0
        push 0
        push NULL
;;this tries to push the value of msg, when you should be giving its address
;        push msg
lea eax,msg
push eax
        call GetMessage


..uncomment the .BREAK .IF(!eax) so your program can close.


Additional little 'fixes..'

    push SW_SHOWDEFAULT
push CommandLine
    push NULL
mov eax,hInstance
    push eax
    call WinMain



    push hInst
    pop wc.hInstance

No snowflake in an avalanche feels responsible.

ekisner

Thank you both (Especially you Tedd) for your help.  Upon making the corrections, the program loads and runs as expected.

After reviewing these changes and comparing them to the Iczelion tutorial, I noticed that in a few places where he used invoke, several parameters had ADDR in front of the variable and several places did not -- I suspect that was probably my biggest mistake overall (my using or not using LEA when pushing values before calling).

Thanks again guys,

Slugsnack

a little tip :

lea eax, hInstance
    push eax


can be converted to 'push hInstance' instead

similarly, instead of lea for pushing pointers to a string you can just do 'push offset AppName'

raymond

Quote from: Slugsnack on August 31, 2009, 02:44:20 PM
a little tip :

lea eax, hInstance
push eax


can be converted to 'push hInstance' instead

similarly, instead of lea for pushing pointers to a string you can just do 'push offset AppName'

Your first example would certainly depend on which assembler you may be using. With MASM, push hInstance would push the actual content of the variable named hInstance (equivalent to the mov eax,hInstance / push eax sequence) and NOT its memory address (obtained with lea eax,hInstance).
When you assume something, you risk being wrong half the time
http://www.ray.masmcode.com

dedndave

hiyas Mike and Ray,
shouldn't this work on most assemblers ???

        push    ADDR hInstance

i suppose it would generate the lea, huh

next question: isn't the lea going to be neccessary for locals, either way ???

Tedd

I wanted to avoid too much confusion, so just stuck with LEA for the variables (since there were already enough problems for a beginner.)

LEA is necessary for referencing local variables (and parameters) because you can't get the actual address before run-time, since they're referenced as an offset from ebp/esp. Unlike global variables, where their address is known in advance.

If you just want to push the value, then there's no need for the lea, as you can push it directly (as Slugsnack said)

(For MASM) ADDR only works in invoke (where it adds LEA if necessary), you need to use OFFSET anywhere else.
No snowflake in an avalanche feels responsible.

raymond

I made the previous comment because some other assembler(s) (I think NASM is one of them) treat for example:
mov eax,hInstance as load eax with the address of the variable hInstance, and
mov eax,[hInstance] as load eax with the value of the variable.

And thus similarly, push hInstance in such assembler(s) would mean to push its address.
When you assume something, you risk being wrong half the time
http://www.ray.masmcode.com

dedndave

thanks Tedd and Ray
for me, i try to write the code out as it will be assembled - lol
that way, when i look at it with a debugger, i get no surprises
plus, it helps me to learn, i think