News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests

Main Menu

CreateWindow returns zero. 64Bit

Started by Sarel, August 01, 2012, 05:55:57 AM

Previous topic - Next topic

Sarel

I can not get it to work. I simply do not know what is wrong. The simple window program assembles and link OK and all constant defined in the headers work just fine. This has to be 64 bit and GoAsm. I do understand how the example program works that is in the GoAsm manual, but I wanted to use the header files. Thanks for any help.


    #define LINKFILES
    #include c:\goasm\headers\windows.h

; --------------------------------------------------------
DATA SECTION
ALIGN 8
        hInstance   dq 0
        hWnd        DQ 0
        hButton0    dq 0
        hEdit0      dq 0
        idButton0   dq 5001
        idEdit0     dq 6001


        szClassName     db 'SarelClass',0
        szDisplayName   db 'Hallo Sarel',0
       
        szButtonClass   db 'BUTTON',0
        szEditClass     db 'EDIT',0
       
        szCaption1      db 'Error1',0
        szText1         db 'RegisterWindow failed',0

; --------------------------------------------------------   
CODE SECTION

START:
   
        INVOKE GetModuleHandleA,0
        mov [hInstance],RAX
        invoke WinMain,[hInstance],0,0,SW_SHOWDEFAULT
        invoke ExitProcess,rax

; --------------------------------------------------------
WinMain frame hInst, hPrevInst, CmdLine, CmdShow

        LOCAL wc:WNDCLASSEX
        LOCAL msg:MSG

        mov D[wc.cbSize],sizeof WNDCLASSEX
        mov D[wc.style],CS_HREDRAW or CS_VREDRAW or CS_BYTEALIGNWINDOW
        mov Q[wc.lpfnWndProc],ADDR WndProc
        mov D[wc.cbClsExtra],0
        mov D[wc.cbWndExtra],0
        mov rax,[hInst]
        mov [wc.hInstance],rax
        invoke LoadIcon,[hInst],500
        mov Q[wc.hIcon],rax
        invoke LoadCursor,0,IDC_ARROW
        mov Q[wc.hCursor],rax
        mov Q[wc.hbrBackground],COLOR_WINDOW+1
        mov Q[wc.lpszMenuName],0
        mov Q[wc.lpszClassName],ADDR szClassName
        mov Q[wc.hIconSm],0

        invoke RegisterClassEx,ADDR wc

        invoke CreateWindowEx,WS_EX_OVERLAPPEDWINDOW,\
                              ADDR szClassName,\
                              ADDR szDisplayName,\
                              WS_OVERLAPPEDWINDOW,\
                              [20],[20],[500],[400],\
                              0,0,\
                              [hInst],0

    cmp rax,0
    jne >> Over
    invoke MessageBox, NULL, 'CreateWindow failed', 'ERROR', MB_OK
    invoke ExitProcess,0
  Over:
 
        mov   Q[hWnd],rax
       
        invoke ShowWindow,[hWnd],SW_SHOWNORMAL
        invoke UpdateWindow,[hWnd]

    StartLoop:
      invoke GetMessage,addr msg,0,0,0
      cmp eax,0
      je >> ExitLoop
      invoke TranslateMessage,ADDR msg
      invoke DispatchMessage,ADDR msg
      jmp StartLoop
    ExitLoop:
     
      mov rax,[msg.wParam]
      ret

endf

; --------------------------------------------------------
WndProc frame hWin, uMsg, wParam, lParam
    USES rbp,rbx,rsi,rdi

    LOCAL hDC:Q
    LOCAL rct:RECT
    LOCAL ps:PAINTSTRUCT
   
        mov eax,[uMsg]
        cmp eax,WM_DESTROY
        je >> Msg1
       
        jmp DefaultProc
      Msg1:
        invoke PostQuitMessage,0
        xor rax,rax
        ret

       DefaultProc:
      INVOKE DefWindowProc, [hWnd], [uMsg], [wParam], [lParam]
      ret

endf

jj2007

What are these brackets good for??

[20],[20],[500],[400]

Yuri

Yes, remove the brackets, and also change the first parameter of your window proc from hWin to hWnd. After those corrections it worked for me.

Sarel

Those brackets ?? I dont know... Battle scars.
There were TopX, TopY, Width and Height in there once. It didnt look wrong until the question was asked. :icon_mrgreen:

I changed the hWin to hWnd also. But this did not work. When I comment out the message box part the program runs but does not show. I need to end the process in task manager.

Below is my batch file that I use

cls
path = c:\goasm\headers;c:\Goasm
set INCLUDE=c:\goasm\headers
GoAsm /l /x64 Hi.asm
GoLink Hi.obj user32.dll kernel32.dll gdi32.dll

Yuri

Quote from: Sarel on August 02, 2012, 04:22:10 AM
I changed the hWin to hWnd also. But this did not work.
The only thing I changed in your code, except this and the brackets, was the path for windows.h, so I don't have any more ideas at the moment. Your program works for me and I can see the window. I am on Win7 x64 SP1.

Sarel

I'm on Win 7 64 bit Ultimate. Also service pack 1. My goasm files are all newly downloaded. Even my hard drive is newly formatted and reloaded. Previously I tried Masm 64bit, but that was a disaster. Strangely the CreateWindow also returned zero then.  I can still use the same method as in the GoAsm example but then I need to build my own header file as some of the structures and constants get duplicated. Thanks for your support and also to every one who helped Shankle with his problems. It helped me set up and use the header files.

Sarel

I am trying again with this window.
Below is the listing for the program. When I assemble it for 32bit (/x86 in the batch file) it shows up on screen. When assembling for 64 bit (/x64) with the two d type indicators (for wc.hbrBackground and wc.lpszMenuName ) changed to q it assembles and build the executable file. The window never shows and the program needs to be stopped by stopping the process. Right after RegisterClass I have GetClassInfo which fails. On my PC the message is "Class does not exist" The RegisterClass function executes successfully.

Please help.

    #define LINKFILES
    #include c:\goasm\headers\windows.h

; --------------------------------------------------------
DATA SECTION
ALIGN 8
        hinst       dq 0
        ptrCmdLine  dq 0
        hButton0    dq 0
        hEdit0      dq 0
        idButton0   dq 5001
        idEdit0     dq 6001
       
        szClassName     db "SarelKlas",0
        szDisplayName   db "Hallo Sarel",0
        szButtonClass   db "BUTTON",0
        szEditClass     db "EDIT",0

; --------------------------------------------------------   
CODE SECTION

START:
ALIGN 8
        INVOKE GetModuleHandle,0       
        mov [hinst],RAX
        invoke GetCommandLine
        mov [ptrCmdLine],rax
        invoke WinMain,[hinst],0,rax,SW_SHOW
        invoke ExitProcess,rax

; --------------------------------------------------------
WinMain frame hInst, hPrevInst, CmdLine, CmdShow

        LOCAL wc:WNDCLASS
        LOCAL sc:WNDCLASS
        LOCAL msg:MSG
        LOCAL hWnd:q
        LOCAL Temp:q

        invoke SetLastError,0

        mov D[wc.style],CS_HREDRAW or CS_VREDRAW or CS_BYTEALIGNWINDOW
        mov rax,addr WndProc
        mov [wc.lpfnWndProc],rax
        mov D[wc.cbClsExtra],0
        mov D[wc.cbWndExtra],0
        mov rax,[hInst]
        mov [wc.hInstance],rax
        invoke LoadIcon,0,IDI_APPLICATION
        mov [wc.hIcon],rax
        invoke LoadCursor,0,IDC_ARROW
        mov [wc.hCursor],rax
        mov d[wc.hbrBackground],COLOR_WINDOW+1
        mov d[wc.lpszMenuName],0
        mov rax,addr szClassName
        mov [wc.lpszClassName],rax
        invoke RegisterClass,addr wc            ;address of the class structure to register
        mov [Temp],rax

        invoke GetClassInfo,[hInst],addr szClassName,addr sc

    cmp rax,0
    jne > Over0
    ;invoke MessageBox, NULL, 'GetClassInfo failed', 'ERROR', MB_OK
    invoke  GetLastError
    sub     esp,512
    xor     ecx,ecx
    mov     edx,esp
    invoke  FormatMessage,FORMAT_MESSAGE_FROM_SYSTEM,ecx,eax,ecx,edx,512,ecx
    mov     edx,esp
    xor     ecx,ecx
    invoke  MessageBox,ecx,edx,ecx,ecx
    add     esp,512
    invoke  ExitProcess,0
  Over0:

        invoke CreateWindow,addr szClassName,addr szDisplayName,\
            WS_OVERLAPPEDWINDOW or WS_VISIBLE,\
            20,20,500,400,\
            0,0,\
            [hInst],0
        mov [hWnd],rax

    cmp rax,0
    jne > Over1
    ;invoke MessageBox, NULL, 'CreateWindowEx failed', 'ERROR', MB_OK
    invoke  GetLastError
    sub     esp,512
    xor     ecx,ecx
    mov     edx,esp
    invoke  FormatMessage,FORMAT_MESSAGE_FROM_SYSTEM,ecx,eax,ecx,edx,512,ecx
    mov     edx,esp
    xor     ecx,ecx
    invoke  MessageBox,ecx,edx,ecx,ecx
    add     esp,512
    invoke  ExitProcess,0
  Over1:

        invoke ShowWindow,[hWnd],[CmdShow]
        invoke UpdateWindow,[hWnd]


      StartLoop:
        invoke GetMessage,addr msg,0,0,0
        cmp eax,0
        je > ExitLoop
        invoke TranslateMessage,ADDR msg
        invoke DispatchMessage,ADDR msg
        jmp StartLoop
      ExitLoop:
     
        mov rax,[msg.wParam]
        ret

endf

; --------------------------------------------------------
WndProc frame hWin, uMsg, wParam, lParam
    USES rbp,rbx,rsi,rdi

    LOCAL hDC:q
   
        mov eax,[uMsg]
        cmp eax,WM_DESTROY
        je > msgDestroy
        cmp eax,WM_CREATE
        je > msgCreate
        jmp > DefaultProc
      msgDestroy:
        invoke PostQuitMessage,0
        xor rax,rax
        ret
      msgCreate:
        xor eax,eax
        ret

       DefaultProc:
      INVOKE DefWindowProc, [hWin], [uMsg], [wParam], [lParam]
      ret

endf

shankle

I'm hardly the one to be giving advice but doesn't the Winmain statement
need to be something like this:
   "invoke WinMain, [hInstance],NULL,[CommandLine],SW_SHOWDEFAULT"
I am doing one in 32-bit so maybe it is different from yours.
Running Windows 7 Pro 32-bit.

dedndave

when he invoke's WinMain, RAX holds a pointer to the command line string
SW_SHOW, SW_SHOWDEFAULT - i doubt that it matters much
it seems that windows substitutes the default value from STARTUPINFO
the first time ShowWindow is called, anyways

the WinMain invoke is strictly a compiler construct
it has nothing to do with how the kernel loads and executes the program
the kernel does not look for this function, nor does it ever attempt to reference it
so - you can eliminate that call if you like

i believe the WinMain construct shows up in a lot of assembly code because
the guys that figured out how to write windows programs in assembler did so
by disassembling C-compiled programs
they saw the WinMain construct and stayed with it - lol
it is, of course, described in MSDN documentation, as well
but, it is described for the benefit of programmers that use compilers

while we're on the subject, the command line pointer that is passed to a compiled WinMain
is pre-parsed, so it would not be exactly correct to pass the command line pointer as is

in an actual compiled program there are a lot of other things that happen before WinMain is called
for example, if you use certain parts of MSVCRT.DLL, some initialization may be performed
i am sure that other things happen, as well - such as InitCommonControlsEx, FPU initialization, and so on
the compiler knows which functions are used and performs the required init
as assembly language programmers, we are responsible for all that stuff, ourselves

japheth

You're using WNDCLASS and RegisterClass instead of WNDCLASSEX and RegisterClassEx.

This is probably not a good decision, because WNDCLASS will cause problems if structure alignment isn't set properly to QWORD. OTOH, WNDCLASSEX is "by design" properly aligned to QWORD, and hence a missing struct alignment doesn't matter there.

A quick lookk at the listing or a disassembly will tell you whether everything is ok.

wjr

GoAsm handles proper structure alignment, so WNDCLASS and RegisterClass should still be fine. The listing does not go into LOCAL expansion details, so it was not readily apparent, but the size was off. I believe all that you need to do is put this before your #include line:

#define WIN64

That will give you the 64-bit structures instead of the 32-bit ones.

Sarel

#define WIN64

YES !! The window is there. I added that as the first line. Thank you wjr. I have been having a hard time with this. Also thanks to dedndave for the GetlastError / FormatMessage.

Now I can start with the 64 bit assembler and find out what changed. Things like mov [wc.lpfnWndProc],addr WndProc does not work. First move the address into a register and then into a memory location. That GetlastError helped me there as well.

I hope this simple window program can help others start faster than I did. Comming from 32 bit this program looks very similar. Also I hope something similar can be included as an example with the GoAsm manual. The current example2 defines its own structures and when you want to use the header files those structure clash.

Thanks every one.