child win creation in a MDI fails using CreateWindowEx

Started by Rainstorm, August 03, 2011, 11:31:05 PM

Previous topic - Next topic

dedndave

first - it isn't mine   :P
i think Hutch wrote that one   :U

with Hutch's code, always have a quick look at the include file(s)   :bg
may be something in there of interest

after that...
in the mdidemo.asm file, look at the 3 procs at the end of the file
in the WndProc function, the left button calls MakeMDIWin
if you want to create more than one child, you will need an array for the handles
he uses the same variable over and over for the demo (mdihWnd)

he registers and creates the main window in WinMain

baltoro

RAINSTORM,   
Hutch's example passes no MDICREATESTRUCT to CreateWindowEx. The last parameter is NULL. Which is weird because the MSDN documentation suggests passing the MDICREATESTRUCT when creating a child window. :eek
Baltoro

dedndave

a pointer to the MDICREATESTRUCT structure is passed to MDI child windows WndProc upon WM_CREATE
lParam, i think, points to the structure
during create, you may alter values in the structure before returning

i dunno - may be you can pass one to CreateWindowEx, as well
but it is easier just to modify the one it sends to you   :P
it's all filled in - you just make any necessary changes

maybe i read the docs wrong, too   :P

here we go...
QuoteWhen the MDI client window creates an MDI child window by calling CreateWindow, the system sends a WM_CREATE message to the created window. The lParam member of the WM_CREATE message contains a pointer to a CREATESTRUCT structure. The lpCreateParams member of this structure contains a pointer to the MDICREATESTRUCT structure passed with the WM_MDICREATE message that created the MDI child window
sounds a little confusing - lol
it hardly makes sense that you would...
create the structure
wait for the pointer to be passed
dereference it twice
then, modify it

a little experimentation should be easy enough

baltoro

DAVE !!! I think you're onto something here,...
I was reading the documentation for CreateWindowEx,...and it says: " If an MDI client window calls CreateWindow to create an MDI child window, lpParam  (the last parameter) should point to a MDICREATESTRUCT structure. lpParam may be NULL if no additional data is needed."
In my MDI application that I mentioned, above, I call CreateWindowEx to create the MDI child window in the handler for WM_CREATE message in the Windows Procedure for the Frame Window just after creating the Client Window,...and I had to pass the window handle for the Frame Window (instead of the handle for the Client Windows as the documentation directs) to get it to work. This is what RAINSTORM does in his code (calling CreateWindowEx from the Frame Window's Window Procedure), except that he passes the window handle of the Client window.
Baltoro

dedndave

right - 3 "levels" of windows, eh ?
Frame - Client - Child
more stuff to learn   :P

you only have to register 2 classes, though
MDICLIENT is a pre-registered system class
the Frame class is similar to a regular window
then, the Child class is a bit different

i guess you can create the Frame window in Winmain and the Client window in WM_CREATE
i am also noticing that they have special DefWindowProc's
DefFrameProc
DefMDIChildProc
sooooo, i guess the Client window still uses DefWindowProc   :red

baltoro

That's the mysterious part,...I have no idea what the Window Peocedure is for the Client Window,...but. it has one, because an alternate technique for creating a child window is to send a WM_MDICREATE Message to the Client Window. The documentatation for CreateWindowEx says this about the MDICLIENT Window Class: "Designates an MDI client window. This window receives messages that control the MDI application's child windows."
And, Child Window Procedure is: DefMDIChildProc Function

My best guess at this point is just to move the MDI Child Window creation code out of the WM_CREATE message handler in the Window procedure for the Frame Window. This is what hutch does in his example that you mentioned previously. In my MDI application. the MDI Child Window creation code resides elsewhere (however, DirectX is a special case).
Baltoro

dedndave

doesn't sound too bad   :P
i have the RegisterClassEx stuff written and WndProc for the Frame started
after my nap - i will play some more

i think the hardest part is keeping track of ID's and handles for the children

oh
it says we should allow extra bytes for each child window
wc.cbWndExtra    = CBWNDEXTRA
i haven't found how big that is, yet   :P

Rainstorm

baltoro wrote..
QuoteHutch's example passes no MDICREATESTRUCT to CreateWindowEx. The last parameter is NULL. Which is weird because the MSDN documentation suggests passing the MDICREATESTRUCT when creating a child window...
I think its kind of optional depending on what you are doing & if you want to pass some info, moreso with CreateWindowEx than the other methods.. since CreatewindowEx already passes a lot of info.
I just tried with the last param '0' instead of' addr mdics'.... still the same thing
QuoteIn my MDI application that I mentioned, above, I call CreateWindowEx to create the MDI child window in the handler for WM_CREATE message in the Windows Procedure for the Frame Window just after creating the Client Window,...and I had to pass the window handle for the Frame Window (instead of the handle for the Client Windows as the documentation directs) to get it to work.
baltoro the sdk says, that the client window handle has to be passed while creating a child window - I use the hwnd from the frame Proc, WM_CREATE to create the client window, & then the hwndclient to create the child win [I've tried with the frame handle too though cause yuo suggested it earlier on & it didn't work]
QuoteThat's the mysterious part,...I have no idea what the Window Peocedure is for the Client Window,...but. it has one, because ...
The client procedure is managed by the system, cause its a system class 'MDICLIENT'
Quotei think the hardest part is keeping track of ID's and handles for the children..
windows takes care of that for you, ID's (not sure in the case where you use the CreateWindowEX method to create the child though)

===========================
This part is off topic but am posting it in case someone else has teh same prob.
I couldn't get a rebar control to display a week back, & it seems (google) that, it was because of a problem/bug with some versions of commctrl.h - its fixed in later versions though

thx!




baltoro

Interesting.
Do you think the Client Window has for some inexplicable reason been destroyed ???
You could try calling GetWindowLong Function (which takes a window handle), using, for the Index, GWL_WNDPROC to retrieve the address of the window procedure. I'll bet you get the same 1400 error.
Baltoro

Rainstorm

 the grey part ias the client window so its being displayed...

EDIT : tried what you said though & GetWindowLong returns nonzero

baltoro

Damn !!! I'm stumped. The code is well-written, and, looks like it should work,...
The documentation says the the usual reason for CreateWindowEx failing is an invalid parameter,...you undoubtedly read this,...
Baltoro

Rainstorm

hi baltoro,
I'll go through it again in a little while, might be some flag or something in the class, like dave said - though the sdk usually mentions if something will explicityly cause a prob
..appreciate all the feedback
Rainstorm.

dedndave

ok - i figured out why you are getting the creation error
when you create a window, the WndProc function is called during creation (before CreateWindow returns)
i believe this applies to pretty much all windows
at that time, the global variable where you store the handle has not been initialized
your MDI child WndProc function looks like this...
DefChildWindowProc proc HWnddefchild:DWORD, uMsg:DWORD, wParam:DWORD, lParam:DWORD

default_processing:
      invoke DefMDIChildProc, hwnddefchild, uMsg, wParam, lParam       ; default processing
      ret

DefChildWindowProc endp

notice the handle name in the invoke   :P
using the local value fixes that problem
      invoke DefMDIChildProc, HWnddefchild, uMsg, wParam, lParam       ; default processing

still, no child window, yet   :'(

dedndave

ok - got it going

1) i had to uncomment .586 for masm - not sure if it is needed for JwAsm
2) i made the change mentioned in my previous post
      invoke DefMDIChildProc, HWnddefchild, uMsg, wParam, lParam       ; default processing
3) the chr$() macro creates zero-terminated strings - no need to add ("",0) - not a problem, but i took them out
4) uncommented the MDICREATESTRUCTURE fill code
5) commented out the message box ;fn MessageBox,0,str$(hwndclient),"hwndclient",MB_OK
6) made 3 changes to CreateWindowEx for the child:
a) added WS_OVERLAPPEDWINDOW to the style bits - not sure why this is needed in this case   :P
b) changed the X position from CW_USEDEFAULT to 50
c) replaced ID_FIRSTDEFCHILD with NULL - this value goes in the CREATESTRUCT for the client window

those changes get us a child window
however, the upper corners are not painted properly
what i did to fix that was....
i removed the CreateWindowEx call for the child from the WM_CREATE handler
i made a routine out of it, then called it just before the message loop

this "corner paint" issue and the need for WS_OVERLAPPEDWINDOW are probably related
there may be some other bit we are not twiddling correctly   :P

i also cleaned up the class register code a little, and changed the icon to IDI_APPLICATION
      mov ebx, hInstance                                  ; handle to the current instance of the application
      invoke LoadIcon,ebx, IDI_APPLICATION
      mov frame_wcl.hIcon,            eax                 ; ALT+TAB icon etc
      mov frame_wcl.hIconSm,          eax                 ; window's title bar icon etc
      mov defchild_wcl.hIcon,         eax                 ; ALT+TAB icon etc
      mov defchild_wcl.hIconSm,       eax                 ; window's title bar icon etc
      invoke LoadCursor, NULL, IDC_ARROW                  ; predefined cursor (could use LoadImage)
      mov frame_wcl.hCursor,          eax
      mov defchild_wcl.hCursor,       eax

      mov frame_wcl.cbSize,           sizeof WNDCLASSEX
      mov frame_wcl.style,            CS_HREDRAW or CS_VREDRAW or CS_BYTEALIGNWINDOW
      mov frame_wcl.lpfnWndProc,      offset FrameWindowProc
      mov frame_wcl.cbClsExtra,       0                   ; 0 = extra memory not used, 40bytes max
      mov frame_wcl.cbWndExtra,       0
      mov frame_wcl.hInstance,        ebx
      mov frame_wcl.hbrBackground,    COLOR_BTNFACE+1
      mov frame_wcl.lpszMenuName,     offset menu_name    ; automatically assigns the menu to the window when its created
      mov frame_wcl.lpszClassName,    offset wclassname

   invoke RegisterClassEx, addr frame_wcl                 ; register the frame class

      mov defchild_wcl.cbSize,        sizeof WNDCLASSEX
      mov defchild_wcl.style,         CS_HREDRAW or CS_VREDRAW or CS_BYTEALIGNWINDOW
      mov defchild_wcl.lpfnWndProc,   offset DefChildWindowProc
      mov defchild_wcl.cbClsExtra,    0                   ; 0 = extra memory not used, 40bytes max
      mov defchild_wcl.cbWndExtra,    32
      mov defchild_wcl.hInstance,     ebx
      mov defchild_wcl.hbrBackground, COLOR_BTNFACE+1
      mov defchild_wcl.lpszMenuName,  0                   ; NULL since a child window can't have its own menu
      mov defchild_wcl.lpszClassName, offset defchildwin_classname

   invoke RegisterClassEx, addr defchild_wcl              ; register the default child window class


it still needs work
the window is not added to the window menu for some reason - we may need to put stuff in the menu

anyways, here is the modified source...

Rainstorm

I made the change to default child handle in the windproc..After that i too was trying stuff.. some of the things you mentioned in your last post, like 'replaced ID_FIRSTDEFCHILD with NULL '...... but individually.
>> i had to uncomment .586 for masm - not sure if it is needed for JwAsm
am using jwasm & i specify that on the command line,(-9) so i had commented it off.

Thx!