Search code examples
assemblyx86masm

error a2070 invalid instruction operands


I'm newbie in Win32 Assembly:

I learn code this program, it's Window simple. But I get the error:

error a2070 invalid instruction operands (MASM)

I have searched on google about this error, but I still don't understand.

.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

WinMain PROTO :HINSTANCE, :HINSTANCE, :LPSTR, :DWORD

.data
    AppName     db "First Windows", 0
    ClassName   db "Window Class", 0

.data?
    hInstance   dd ?
    CommandLine dd ?

.code
start:
    invoke  GetModuleHandle, NULL
    MOV     hInstance, EAX
    invoke  GetCommandLine
    MOV     CommandLine, EAX
    invoke  WinMain, hInstance, NULL, CommandLine, SW_SHOWDEFAULT
    invoke  ExitProcess, EAX

    WinMain PROC ahInstance:HINSTANCE, \
            ahPrevInstance:HINSTANCE, \
            aCommandLine:LPSTR, \
            aCommandShow:DWORD
        LOCAL   wc:WNDCLASSEX
        LOCAL   hwnd:HANDLE
        LOCAL   msg:MSG

        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
        MOV     wc.hInstance, hInstance ;;;;;;;;;;;;;;;; Error here

        invoke  LoadIcon, NULL, IDI_APPLICATION
        MOV     wc.hIcon, EAX
        MOV     wc.hIconSm, EAX
        invoke  LoadCursor, NULL, IDC_ARROW
        MOV     wc.hCursor, EAX
        MOV     wc.hbrBackground, COLOR_WINDOW+1
        MOV     wc.lpszMenuName, NULL
        MOV     wc.lpszClassName, offset ClassName

        invoke  RegisterClassEx, addr wc

        invoke  CreateWindowEx, NULL, addr ClassName, addr AppName, \
                WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, \
                CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, ahInstance, NULL
        MOV     hwnd, EAX

        invoke  ShowWindow, hwnd, SW_SHOWNORMAL
        invoke  UpdateWindow, hwnd

        .WHILE TRUE
            invoke  GetMessage, addr msg, NULL, 0, 0
            .BREAK .IF (!EAX)
            invoke  TranslateMessage, addr msg
            invoke  DispatchMessage, addr msg
        .ENDW

        MOV EAX, msg.wParam
        RET
    WinMain endp

    WndProc PROC ahWnd:HWND, aMsg:DWORD, awParam:WPARAM, alParam:LPARAM
        .IF aMsg == WM_DESTROY
            invoke  PostQuitMessage, NULL
        .ELSE
            invoke  DefWindowProc, ahWnd, aMsg, awParam, alParam
            ret
        .ENDIF
        XOR EAX, EAX
        ret
    WndProc endp
end start

That line:

MOV     wc.hInstance, hInstance

gets an error, I replace by:

PUSH hInstance
POP  wc.hInstance

--> this is OK.

But I don't understand WHY ???

Anyone can help me.


Solution

  • wc.hInstance refers to a part of wc, which is on the stack, and is thus in memory. hInstance is also on the stack, and is thus in memory. If you try any memory-to-memory move, you'll notice that it doesn't work:

    mov [esp], [ebp]
    error: invalid operand.
    

    That's just a limitation of the x86 instruction set; the x86 instruction set has no memory-to-memory move. You'll have to make it into two instructions like you did with push and pop.