News:

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

Main Menu

CreateWindowEx fails

Started by GoneFishing, March 24, 2013, 01:43:45 AM

Previous topic - Next topic

GoneFishing

Hi all,

I'm trying to create simple window with status bar. My window appears without it. CreateWindowEx returns nothing.

Here is the code:

.486
.model flat, stdcall
option casemap:none

include  \masm32\include\comctl32.inc
include  \masm32\include\comdlg32.inc
include  \masm32\include\windows.inc
include  \masm32\include\kernel32.inc
include  \masm32\include\user32.inc
include  \masm32\include\gdi32.inc

includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\user32.lib
includelib \masm32\lib\gdi32.lib
includelib \masm32\lib\comctl32.lib
includelib \masm32\lib\comdlg32.lib



WinMain PROTO STDCALL   :DWORD, :DWORD, :DWORD, :DWORD
WndProc PROTO STDCALL   :DWORD, :DWORD, :DWORD, :DWORD

.data?

hInstance       dd      ?
hWndStat        dd      ?
sbParts         dd   4  dup(?)
hwnd            dd      ?

.data

StatClass       db      "msctls_statusbar32",0
ClassName       db      "FirstWindowClass",0
AppName         db      "StatusBar",0

.code

start:

    invoke  GetModuleHandle, NULL
    mov     hInstance, eax
    call    InitCommonControls
    invoke  WinMain, hInstance, NULL, NULL, SW_SHOWNORMAL
    invoke  ExitProcess, NULL

WinMain proc hInst:HINSTANCE,hPrevInst:HINSTANCE,CmdLine:LPSTR,CmdShow:DWORD
    LOCAL  wc:WNDCLASSEX
    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
    push    hInst
    pop     wc.hInstance
    mov     wc.hbrBackground,COLOR_WINDOW
    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
   
    INVOKE CreateWindowEx,WS_EX_CLIENTEDGE,ADDR ClassName,ADDR AppName,\
           WS_OVERLAPPEDWINDOW-WS_SIZEBOX-WS_MAXIMIZEBOX,CW_USEDEFAULT,\
           CW_USEDEFAULT,400,300,NULL,NULL,\
           hInstance,NULL
    mov   hwnd,eax
  ;  invoke LoadMenu,hInst,600  ; menu ID
  ;  invoke SetMenu,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 hWnd:DWORD, uMsg:DWORD, wParam:DWORD, lParam:DWORD
;mov eax, uMsg

.IF  uMsg == WM_CREATE

;---------- Create the status bar window ----------
     invoke  CreateWindowEx, 0, addr StatClass, 0,\
                     WS_CHILD or WS_BORDER or WS_VISIBLE or SBS_SIZEGRIP,\
                    0, 0, 0, 0,hwnd, 0, hInstance, 0 
            mov     hWndStat, eax

.elseif  uMsg == WM_DESTROY
    invoke PostQuitMessage, NULL
.ELSE
    invoke DefWindowProc, hWnd, uMsg, wParam, lParam
    ret
.ENDIF
xor eax,eax
ret
WndProc endp

end start
 

I'm probably missing something :icon_confused:

Waiting for help and critique :icon_redface:

japheth

Quote from: vertograd on March 24, 2013, 01:43:45 AM
Waiting for help and critique :icon_redface:

You probably will have to handle the WM_SIZE message. Within this code you'll have to set the size of the statusbar child ( using SetWindowPos() ).

jj2007

hWnd will do the job. No WM_SIZE handler needed.

GoneFishing

Really?!! :shock:
It looks so simple . I'm going to my "developer" machine to fix it right now
Thank you both!

dedndave

i think that....
if you use CreateStatusWindow, the status bar will size and locate itself
if you use CreateWindowEx to create a status bar, you need to handle size/location of the status bar

jj2007

After creating the main window, you assign the handle to a global variable:
mov hwnd, eax

That is fine, but in the WM_CREATE handler you have not yet reached that point, so hwnd is still zero, and you get a zero return value plus error "Cannot create top level child window".

In contrast, hWnd is already available at this stage.

dedndave

Jochen makes a good point
in fact, i often initialize the global hWin variable as the first step of handling WM_CREATE (from hWnd value)
it is the earliest point in the sequence of events that you know the window handle

GoneFishing

Thank you, jj2007!

I've just fixed the code.Now all works well!
I've already realized my mistake. I've missed the difference between global hwnd and local hWnd variables.
It's a shame of me. 

Then I added WM_SIZE handling routine and my status bar appeared as was expected.
Thanks, Dave
I'll try that function to create a status bar.
And one more question ...
How can I create menu item that can be checked /unchecked?

jj2007

Quote from: dedndave on March 24, 2013, 02:30:34 AMinitialize the global hWin variable as the first step of handling WM_CREATE (from hWnd value)

Dave,
You are wasting 3 (three!) precious bytes:

   mrm hwnd, hWnd  ; 8 bytes
   mov hwnd, eax   ; 5 bytes

:eusa_naughty:

dedndave

the easiest way to create menus is in the resource file
here is one example that includes accelerators
view the masm32\bin\rc.hlp file for more info
;Simple MDI Window - DednDave - 5, 2012

;#####################################################################################

#include "\masm32\include\resource.h"

#ifndef  CREATEPROCESS_MANIFEST_RESOURCE_ID
#define  CREATEPROCESS_MANIFEST_RESOURCE_ID  1
#endif

#ifndef  RT_MANIFEST
#define  RT_MANIFEST                         24
#endif

#ifndef  VS_VERSION_INFO
#define  VS_VERSION_INFO                     1
#endif

#ifndef  VOS_NT_WINDOWS32
#define  VOS_NT_WINDOWS32                    0x00040004L
#endif

#ifndef  VFT_APP
#define  VFT_APP                             0x00000001L
#endif

;*************************************************************************************

#define  IDI_ICON                            100
#define  IDM_MAINMENU                        543
#define  IDM_FILENEW                         544
#define  IDM_FILEEXIT                        545
#define  IDM_FILEWINDOW_TILEHORZ             549
#define  IDM_FILEWINDOW_TILEVERT             550
#define  IDM_FILEWINDOW_CASCADE              551
#define  IDM_FILEWINDOW_ARRANGE              552
#define  IDA_ACC                             999

;#####################################################################################

IDI_ICON  ICON  DISCARDABLE  "SimpleMDI.ico"

;#####################################################################################

IDM_MAINMENU  MENU
  BEGIN
    POPUP             "&File"
      BEGIN
        MENUITEM      "&New\tCtrl+N",                IDM_FILENEW
        POPUP         "&Arrange"
          BEGIN
            MENUITEM  "&Cascade\tCtrl+C",            IDM_FILEWINDOW_CASCADE
            MENUITEM  "Tile &Horizontally\tCtrl+H",  IDM_FILEWINDOW_TILEHORZ
            MENUITEM  "Tile &Vertically\tCtrl+V",    IDM_FILEWINDOW_TILEVERT
            MENUITEM  "Arrange Icons\tCtrl+I",       IDM_FILEWINDOW_ARRANGE
          END
        MENUITEM      SEPARATOR
        MENUITEM      "E&xit\tCtrl+X",               IDM_FILEEXIT
      END
  END

;*************************************************************************************

IDA_ACC  ACCELERATORS
  BEGIN
    "N",  IDM_FILENEW,              VIRTKEY,  CONTROL,  NOINVERT
    "C",  IDM_FILEWINDOW_CASCADE,   VIRTKEY,  CONTROL,  NOINVERT
    "H",  IDM_FILEWINDOW_TILEHORZ,  VIRTKEY,  CONTROL,  NOINVERT
    "V",  IDM_FILEWINDOW_TILEVERT,  VIRTKEY,  CONTROL,  NOINVERT
    "I",  IDM_FILEWINDOW_ARRANGE,   VIRTKEY,  CONTROL,  NOINVERT
    "X",  IDM_FILEEXIT,             VIRTKEY,  CONTROL,  NOINVERT
  END

;#####################################################################################

; manifest file

CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "SimpleMDI.xml"

;#####################################################################################

; file version info

VS_VERSION_INFO VERSIONINFO
FILEVERSION     1,0,0,0
PRODUCTVERSION  1,0,0,0
FILEOS          VOS_NT_WINDOWS32
FILETYPE        VFT_APP
BEGIN
  BLOCK "StringFileInfo"
  BEGIN
    BLOCK "040904E4"
    BEGIN
      VALUE "CompanyName",      "DednDave\000"
      VALUE "FileDescription",  "Simple MDI Window\000"
      VALUE "FileVersion",      "1.0\000"
      VALUE "LegalCopyright",   "\251 2012 David R. Sheldon\000"
    END
  END
  BLOCK "VarFileInfo"
  BEGIN
    VALUE "Translation", 0x409, 0x4E4
  END
END

;#####################################################################################

dedndave

Quote from: jj2007 on March 24, 2013, 02:39:49 AM
Quote from: dedndave on March 24, 2013, 02:30:34 AMinitialize the global hWin variable as the first step of handling WM_CREATE (from hWnd value)

Dave,
You are wasting 3 (three!) precious bytes:

   mrm hwnd, hWnd  ; 8 bytes
   mov hwnd, eax   ; 5 bytes

:eusa_naughty:
not really
i usually load the hWnd value into a register, like EBX, then use it throughout WM_CREATE
so, that is a good time to store it   :P

GoneFishing

So I can create such checkable menu item by means of resource file, yes?
Going to look into MASM examples and help

dedndave

yes - that is the easy way
and, ultimately, you will probably want a resource file, anyways

there are a few ways to load a menu from resource
you can use LoadMenu, then place the handle in the class structure
you can use LoadMenu, then pass the handle to CreateWindowEx (this is what i usually do)
or, you can use LoadMenu and SetMenu, after the window has been created

the last 2 have more-or-less the same result
the first one is slightly different in that all windows of that class will have the same menu

there are a number of functions, etc, associated with menus
http://msdn.microsoft.com/en-us/library/windows/desktop/ff468864%28v=vs.85%29.aspx

jj2007

Quote from: vertograd on March 24, 2013, 02:38:48 AM
I've missed the difference between global hWnd and local hwnd variables.
It's a shame of me.
Reserve shame for more serious errors :badgrin:
Besides, hWnd is a passed argument, not a local variable.

QuoteThen I added WM_SIZE handling routine and my status bar appeared as was expected.
The status bar is a grown-up control, it does not need parental assistance to size itself.

QuoteHow can I create menu item that can be checked /unchecked?

Something like this?

      mov hMenu, rv(CreateMenu)         ; create the main menu (hMenu is a global var)
      mov hM1, rv(CreateMenu)            ; plus two
      mov hM2, rv(CreateMenu)            ; sub menus
      invoke AppendMenu, hMenu, MF_POPUP, hM1, chr$("&File")
      invoke AppendMenu, hM1, MF_STRING, IdMenuNew, chr$("&New",9,"Ctrl+N")
      invoke AppendMenu, hM1, MF_STRING, IdMenuSave, chr$("&Save",9,"Ctrl+S")
      invoke AppendMenu, hMenu, MF_POPUP, hM2, chr$("&Edit")
      invoke AppendMenu, hM2, MF_STRING, IdMenuCopy, chr$("&Copy",9,"Ctrl+C")

dedndave

Quote from: jj2007 on March 24, 2013, 03:25:06 AM
The status bar is a grown-up control, it does not need parental assistance to size itself.
see my previous post
if you use CreateWindowEx to create a status bar, i think you do have to size and locate it
probably a good argument for using CreateStatusWindow, instead

Quote from: jj2007 on March 24, 2013, 03:25:06 AM
QuoteHow can I create menu item that can be checked /unchecked?

Something like this?

      mov hMenu, rv(CreateMenu)         ; create the main menu (hMenu is a global var)
      mov hM1, rv(CreateMenu)            ; plus two
      mov hM2, rv(CreateMenu)            ; sub menus
      invoke AppendMenu, hMenu, MF_POPUP, hM1, chr$("&File")
      invoke AppendMenu, hM1, MF_STRING, IdMenuNew, chr$("&New",9,"Ctrl+N")
      invoke AppendMenu, hM1, MF_STRING, IdMenuSave, chr$("&Save",9,"Ctrl+S")
      invoke AppendMenu, hMenu, MF_POPUP, hM2, chr$("&Edit")
      invoke AppendMenu, hM2, MF_STRING, IdMenuCopy, chr$("&Copy",9,"Ctrl+C")
as you can see from all that code, the resource file method is easier   :P