e or ws_clipchildren,cw_usedefault, cw_usedefault,cw_usedefault,cw_usedefault,hwnd,null,\ hinstance,addr clientstruct mov hwndclient,eax ;======================================= ; initialize the mdicreatestruct ;======================================= mov mdicreate.szclass,offset mdichildclassname mov mdicreate.sztitle,offset mdichildtitle push hinstance pop mdicreate.howner mov mdicreate.x,cw_usedefault mov mdicreate.y,cw_usedefault mov mdicreate.lx,cw_usedefault mov mdicreate.ly,cw_usedefault .elseif umsg==wm_command .if lparam==0 mov eax,wparam .if ax==idm_exit invoke sendmessage,hwnd,wm_close,0,0 .elseif ax==idm_tilehorz invoke sendmessage,hwndclient,wm_mditile,mditile_horizontal,0 .elseif ax==idm_tilevert invoke sendmessage,hwndclient,wm_mditile,mditile_vertical,0 .elseif ax==idm_cascade invoke sendmessage,hwndclient,wm_mdicascade,mditile_skipdisabled,0 .elseif ax==idm_new invoke sendmessage,hwndclient,wm_mdicreate,0,addr mdicreate .elseif ax==idm_close invoke sendmessage,hwndclient,wm_mdigetactive,0,0 invoke sendmessage,eax,wm_close,0,0 .else invoke defframeproc,hwnd,hwndclient,umsg,wparam,lparam ret .endif .endif .elseif umsg==wm_destroy invoke postquitmessage,null .else invoke defframeproc,hwnd,hwndclient,umsg,wparam,lparam ret .endif xor eax,eax ret wndproc endp childproc proc hchild:dword,umsg:dword,wparam:dword,lparam:dword .if umsg==wm_mdiactivate mov eax,lparam .if eax==hchild invoke getsubmenu,hchildmenu,1 mov edx,eax invoke sendmessage,hwndclient,wm_mdisetmenu,hchildmenu,edx .else invoke getsubmenu,hmainmenu,1 mov edx,eax invoke sendmessage,hwndclient,wm_mdisetmenu,hmainmenu,edx .endif invoke drawmenubar,hwndframe .elseif umsg==wm_close invoke messagebox,hchild,addr closepromptmessage,addr appname,mb_yesno .if eax==idyes invoke sendmessage,hwndclient,wm_mdidestroy,hchild,0 .endif .else invoke defmdichildproc,hchild,umsg,wparam,lparam ret .endif xor eax,eax ret childproc endp end start
analysis:
the first thing the program does is to register the window classes of the frame window and the mdi child window. after that, it calls createwindowex to create the frame window. within the wm_create handler of the frame window, we create the client window:
local clientstruct:clientcreatestruct .if umsg==wm_create invoke getmenu,hwnd mov hmainmenu,eax invoke getsubmenu,hmainmenu,1 mov clientstruct.hwindowmenu,eax mov clientstruct.idfirstchild,100 invoke createwindowex,null,addr mdiclientname,null,\ ws_child or ws_visible or ws_clipchildren,cw_usedefault,\ cw_usedefault,cw_usedefault,cw_usedefault,hwnd,null,\ hinstance,addr clientstruct mov hwndclient,eax
it calls getmenu to obtain the handle to the menu of the frame window, to be used in the getsubmenu call. note that we pass the value 1 to getsubmenu because the submenu we want the window list to appear is the second submenu. then we fill the members of the clientcreatestruct structure.
next, we initialize the mdiclientstruct structure. note that we don't need to do it here. it's only convenient to do it in wm_create.
mov mdicreate.szclass,offset mdichildclassname mov mdicreate.sztitle,offset mdichildtitle push hinstance pop mdicreate.howner mov mdicreate.x,cw_usedefault mov mdicreate.y,cw_usedefault mov mdicreate.lx,cw_usedefault mov mdicreate.ly,cw_usedefault
after the frame window is created (and also the client window), we call loadmenu to load the child window menu from the resource. we need to get this menu handle so we can replace the menu of the frame window with it when an mdi child window is present. don't forget to call destroymenu on the handle before the application exits to windows. normally windows will free the menu associated with a window automatically when the application exits but in this case, the child window menu is not associated with any window thus it will still occupy valuable memory even after the application exits.