-1

The program compiles fine, but it fails to create the main window. Specifically, CreateWindowEx fails and prints "Failed to create window".

Would anyone happen to know what I'm doing wrong? I'm following Kip Irvine's book on assembly almost exactly, but it seems I'm missing something.

EDIT: I updated the code based on the recommendations. Now the program fails to register the window class, and the specific error is that a "Parameter is incorrect". I looked over the parameters of my WNDCLASSEX struct, and couldn't fine anything wrong.

EDIT2: I removed the "Ex" from WNDCLASS and RegisterClass and the window shows up and works fine now. So I guess it was some kind of weird redefinition or inconsistency of structs and functions in the masm32rt library?

INCLUDE \masm32\include\masm32rt.inc

.data
windowName BYTE "ASM Windows App",0
className BYTE "ASMWin",0
MainWinClass WNDCLASSEX <NULL,CS_HREDRAW + CS_VREDRAW,WinProc,NULL,NULL,NULL,NULL,NULL,COLOR_WINDOW+1,NULL,className,NULL>
windowHandle DWORD ?
hInstance DWORD ?

.code
WinMain PROC

    ; Get a handle to the current process.
    INVOKE GetModuleHandle, NULL
    mov hInstance, eax
    mov MainWinClass.hInstance, eax

    ; Check if the handle was received.
    .IF eax == 0
        pushad
        print "Failed to get handle on current process"
        popad
        call ErrorHandler
        jmp ExitProgram
    .ENDIF

    ; Load the program's icon and cursor.
    INVOKE LoadIcon, NULL, IDI_APPLICATION
    mov MainWinClass.hIcon, eax
    INVOKE LoadCursor, NULL, IDC_ARROW
    mov MainWinClass.hCursor, eax

    ; Create the window class.
    INVOKE RegisterClassEx, ADDR MainWinClass

    ; Check if the class was registered.
    .IF eax == 0
        pushad
        print "Failed to register class."
        popad
        call ErrorHandler
        jmp ExitProgram
    .ENDIF

    ; Create the window.
    INVOKE CreateWindowEx, 0, ADDR className, ADDR windowName, WS_VISIBLE, 
    CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
    NULL, NULL, hInstance, NULL

    ; Check if window was created successfully.
    .IF eax == 0
        pushad
        print "Failed to create window"
        popad
        call ErrorHandler
        jmp ExitProgram
    .ENDIF

    ; Save the window handle and use it to show the window.
    mov windowHandle, eax
    INVOKE ShowWindow, windowHandle, SW_SHOW
    INVOKE UpdateWindow, windowHandle

    ; Message Loop
    ;MessageLoop:
    ;    INVOKE GetMessage, ADDR msg, NULL, NULL, NULL
    ;    INVOKE DispatchMessage, ADDR msg
    ;    jmp MessageLoop

ExitProgram:
    ;CALL ReadChar
    INVOKE ExitProcess, 0
WinMain ENDP

; Window Procedure
WinProc PROC,
    hWnd:DWORD, localMsg:DWORD, wParam:DWORD, lParam:DWORD
    mov eax, localMsg

    .IF eax == WM_CREATE
        ;call WriteString
        jmp WinProcExit
    .ELSEIF eax == WM_CLOSE
        ;call WriteString
        jmp WinProcExit
    .ELSE
        ;call WriteString
        INVOKE DefWindowProc, hWnd, localMsg, wParam, lParam
        jmp WinProcExit
    .ENDIF

WinProcExit:
    ret
WinProc ENDP

ErrorHandler PROC
.data
pErrorMsg DWORD ?
messageID DWORD ?
.code
    INVOKE GetLastError
    mov messageID, eax

    ; Get the corresponding message string.
    INVOKE FormatMessage, FORMAT_MESSAGE_ALLOCATE_BUFFER + \
    FORMAT_MESSAGE_FROM_SYSTEM,NULL,messageID,NULL,
    ADDR pErrorMsg,NULL,NULL

    ; Display the error message.
    INVOKE MessageBox, NULL, pErrorMsg, NULL,
    MB_ICONERROR+MB_OK

    ; Free the error message string.
    INVOKE LocalFree, pErrorMsg

    ret
ErrorHandler ENDP
END WinMain
rkhb
  • 14,159
  • 7
  • 32
  • 60
Artur
  • 401
  • 1
  • 4
  • 8
  • 1
    What do you mean by it failing to create the main window? Does `CreateWindowEx` fail and the program prints `Failed to create window` or does it print nothing and no windows appears? – Ross Ridge Nov 25 '16 at 04:25
  • @RossRidge CreateWindowEx fails and prints "Failed to create window". I'll make sure to clarify that. – Artur Nov 25 '16 at 04:27
  • 1
    You forgot to call DefWindowProc. – Raymond Chen Nov 25 '16 at 04:42
  • 2
    Also, the second parameter of `CreateWindowEx()` expects a pointer to a null-terminated string for the class name, but you are passing a pointer to your `WNDCLASSEX` struct instead. – Remy Lebeau Nov 25 '16 at 05:11
  • Hmm... I fixed both issues, but it still gives the same failure message. – Artur Nov 25 '16 at 05:21
  • 2
    Use `GetLastError` to determine why `CreateWindowEx` has failed. – Ari0nhh Nov 25 '16 at 05:33
  • 1
    @Artekis Post the updated code. Also check the return value of `RegisterClassEx`. As others said, implement a proper error handling and post the result here. – Margaret Bloom Nov 25 '16 at 10:46
  • @MargaretBloom Thanks for the everyone. I updated the code and the error type in the original post. I am now getting a "Parameter is incorrect" error when trying to register the window class. – Artur Nov 25 '16 at 15:33
  • Does NASM (or your libraries) automatically use `RegisterClassExA`, et cetera, when no particular string style is asked for? – Jongware Nov 25 '16 at 15:36
  • @RadLexus To be sure, I commented out the unnecessary libraries and only kept masm32rt.inc, which is a include file that includes windows.inc, masm32.inc and all of the Windows API inc files. – Artur Nov 25 '16 at 16:16
  • @RadLexus I also checked windows.inc for RegisterClassExA and I couldn't find anything to do with RegisterClass. But I did find the WNDCLASSEX structs in there. – Artur Nov 25 '16 at 16:16
  • @RadLexus Hmm, so I took off the "Ex" from "RegisterClass" and "WNDCLASS" in my code, and the window works perfectly fine. So I think you're right about it. Though I don't exactly know what was wrong in the first place. – Artur Nov 25 '16 at 16:34

1 Answers1

1

WNDCLASSEX requires WNDCLASSEX.cbSize to be set. The mistake I made was that I assumed it could be NULL.

So I added this piece of code before registering the class:

; Initializing other parameters of the window class.
mov eax, SIZEOF MainWinClass
mov MainWinClass.cbSize, eax

In addition, Kip Irvine's functions cause errors when used along side some functions of the user interface section of the Windows API. I'm not exactly sure why that happens but it could be that some register values are changed around.

Artur
  • 401
  • 1
  • 4
  • 8
  • 1
    Note that this will be true for ***all*** WinAPI structures that have a `cbSize` member. Check the online MSDN documentation before calling a function to be sure. – Cody Gray - on strike Nov 26 '16 at 12:43
  • Using the Ex function is pointless if you are not setting the small icon as well. – Anders Mar 18 '17 at 04:27