Jump to content
  • Advertisement
Sign in to follow this  
CTEagle

RESOLVED - MDI Child Creation Problem

This topic is 4466 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I am having a problem creating an MDI Child form. I have made a basic program in order to learn how to do this and I just cannot figure it out. The program that I have automatically creates and displays 2 forms. The first form is a standard SDI form. The 2nd form is a MDIParent with a MDIChild. Both the SDI form and the MDIParent form are displayed. The MDIChild form is not displayed. I have pasted the code for what I have done below. Any help would be greatly appreciated.
#include <windows.h>
LRESULT CALLBACK WindowProc(HWND hMain, UINT message, WPARAM wParam, LPARAM lParam);
LRESULT CALLBACK ParentProc(HWND hParent, UINT message, WPARAM wParam, LPARAM lParam);
LRESULT CALLBACK ChildProc(HWND hChild, UINT msg, WPARAM wParam, LPARAM lParam);
HWND CreateNewMDIChild(HWND hMDIClient);
HWND hMain;
HWND hParent;
HWND hChild;
MSG msg;
	
HWND mdiClientWindow;
MDICREATESTRUCT mcs;

int WINAPI WinMain(HINSTANCE hInstance,	HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow){
	
	

	//This is a standard form
	WNDCLASSEX frmMain;
	
	frmMain.cbSize        = sizeof(WNDCLASSEX);
    frmMain.style         = 0;
	frmMain.cbClsExtra    = 0;
    frmMain.cbWndExtra    = 0;
	frmMain.hInstance     = hInstance;
	frmMain.hIcon		  = NULL;
    frmMain.hCursor       = LoadCursor(NULL, IDC_ARROW);
	frmMain.hbrBackground = (HBRUSH)GetStockObject(LTGRAY_BRUSH);
	frmMain.lpszMenuName  = NULL;	    
    frmMain.hIconSm       = NULL;	    
    frmMain.lpfnWndProc	  = WindowProc;    
	frmMain.lpszClassName = "frmMain";
    
	if(!RegisterClassEx(&frmMain))
    {
        MessageBox(NULL, "Main Window Registration Failed!", "Error!",MB_ICONEXCLAMATION | MB_OK);        
    }
   
	hMain = CreateWindowEx(WS_EX_CLIENTEDGE, "frmMain","frmMain",WS_SYSMENU,CW_USEDEFAULT, CW_USEDEFAULT, 480, 470,NULL, NULL, hInstance, NULL);

	ShowWindow(hMain, nCmdShow);
	UpdateWindow(hMain);	

	//This is a MDIParent
	WNDCLASSEX frmParent;
	
	frmParent.cbSize        = sizeof(WNDCLASSEX);
    frmParent.style         = 0;
	frmParent.cbClsExtra    = 0;
    frmParent.cbWndExtra    = 0;
	frmParent.hInstance     = hInstance;
	frmParent.hIcon		  = NULL;
    frmParent.hCursor       = LoadCursor(NULL, IDC_ARROW);
	frmParent.hbrBackground = (HBRUSH)GetStockObject(LTGRAY_BRUSH);
	frmParent.lpszMenuName  = NULL;	    
    frmParent.hIconSm       = NULL;	    
    frmParent.lpfnWndProc	  = ParentProc;    
	frmParent.lpszClassName = "frmParent";
    
	if(!RegisterClassEx(&frmParent))
    {
        MessageBox(NULL, "frmParent Window Registration Failed!", "Error!",MB_ICONEXCLAMATION | MB_OK);        
    }

	hParent = CreateWindowEx(WS_EX_CLIENTEDGE, "frmParent", "frmParent",WS_SYSMENU,CW_USEDEFAULT, CW_USEDEFAULT, 480, 470,NULL, NULL, hInstance, NULL);
	
	ShowWindow(hParent, nCmdShow);
	UpdateWindow(hParent);	

	//This is a MDIChild
	WNDCLASSEX frmChild;
	
	frmChild.cbSize        = sizeof(WNDCLASSEX);
    frmChild.style         = 0;
	frmChild.cbClsExtra    = 0;
    frmChild.cbWndExtra    = 0;
	frmChild.hInstance     = hInstance;
	frmChild.hIcon		    = NULL;
    frmChild.hCursor       = LoadCursor(NULL, IDC_ARROW);
	frmChild.hbrBackground = (HBRUSH)GetStockObject(LTGRAY_BRUSH);
	frmChild.lpszMenuName  = NULL;	    
    frmChild.hIconSm       = NULL;	    
    frmChild.lpfnWndProc	= ChildProc;    
	frmChild.lpszClassName = "frmChild";
    
	if(!RegisterClassEx(&frmChild))
    {
        MessageBox(NULL, "frmChild Window Registration Failed!", "Error!",MB_ICONEXCLAMATION | MB_OK); 
	}

	
	//CreateNewMDIChild(mdiClientWindow);	
	
	while(GetMessage(&msg, 0,0,0)== TRUE)
	{
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}	
	return 0;
}

LRESULT CALLBACK WindowProc(HWND hMain, UINT message, WPARAM wParam, LPARAM lParam)
{
	switch(message)
	{
	
	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;

	default:
		return DefWindowProc(hMain, message, wParam, lParam);
	}
}

LRESULT CALLBACK ParentProc(HWND hParent, UINT message, WPARAM wParam, LPARAM lParam)
{
	switch(message)
	{
		case WM_CREATE:
		{
			 
			CLIENTCREATESTRUCT ccs;

			ccs.hWindowMenu  = NULL;
			ccs.idFirstChild = 5000;			
			mdiClientWindow = CreateWindowEx(WS_EX_CLIENTEDGE, "mdiclient", NULL, WS_CHILD | WS_CLIPCHILDREN | WS_VSCROLL | WS_HSCROLL | WS_VISIBLE, 
			CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, hParent, NULL, GetModuleHandle(NULL), (LPVOID)&ccs);
			CreateNewMDIChild(mdiClientWindow);	
			
			return 0;			 
		}
	case WM_DESTROY:
		{
			PostQuitMessage(0);
			return 0;
		}

	default:
		
		return DefFrameProc(hParent, mdiClientWindow, message, wParam, lParam);
	}
}

LRESULT CALLBACK ChildProc(HWND hChild, UINT message, WPARAM wParam, LPARAM lParam)
{
	return ChildProc(hChild, message, wParam, lParam);
}

HWND CreateNewMDIChild(HWND mdiClientWindow)
{     
    mcs.szTitle = "Child Form";
    mcs.szClass = "frmChild";
    mcs.hOwner  = GetModuleHandle(NULL);
	mcs.x		= mcs.cx = CW_USEDEFAULT;
    mcs.y		= mcs.cy = CW_USEDEFAULT;
    mcs.style	= MDIS_ALLCHILDstyleS;

    hChild = (HWND)SendMessage(mdiClientWindow, WM_MDICREATE, 0, (LONG)&mcs);
    if(!hChild)
    {
        MessageBox(hParent, "MDI Child creation failed.", "Oh Oh...", MB_ICONEXCLAMATION | MB_OK);
    }
	
    return hChild;
}




[Edited by - CTEagle on July 27, 2006 7:22:06 AM]

Share this post


Link to post
Share on other sites
Advertisement
A tip which should make debugging this a lot easier, and help you figure out this problem.


hChild = (HWND)SendMessage(mdiClientWindow, WM_MDICREATE, 0, (LONG)&mcs);
if(!hChild)
{
MessageBox(hParent, "MDI Child creation failed.", "Oh Oh...",
MB_ICONEXCLAMATION | MB_OK);
}




Rather than place your own Error Messages in, try using the Windows function GetLastError. It will tell you what went wrong.

...<Cut so you can look it up and see for yourself, probably learn better than having me answer this>

Share this post


Link to post
Share on other sites
Thanks for your reply Nytegard.

I used the following code instead of the messagebox that I originally had.

char buffer[256];

FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,0,GetLastError(),MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),buffer,256,0);

MessageBox(hMain,buffer,"Error",MB_OK|MB_ICONERROR);

When I run the program, I get a message stating "The operation completed successfully". Unfortunately, I still do not see the MDIChild window.

Is the GetLastError code I used similar to what you did? Did I place GetLastError in the proper spot in the program?

Share this post


Link to post
Share on other sites
Quote:
Original post by CTEagle
Thanks for your reply Nytegard.

I used the following code instead of the messagebox that I originally had.

char buffer[256];

FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,0,GetLastError(),MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),buffer,256,0);

MessageBox(hMain,buffer,"Error",MB_OK|MB_ICONERROR);

When I run the program, I get a message stating "The operation completed successfully". Unfortunately, I still do not see the MDIChild window.

Is the GetLastError code I used similar to what you did? Did I place GetLastError in the proper spot in the program?



HWND CreateNewMDIChild(HWND mdiClientWindow)
{
mcs.szTitle = "Child Form";
mcs.szClass = "frmChild";
mcs.hOwner = GetModuleHandle(NULL);
mcs.x = mcs.cx = CW_USEDEFAULT;
mcs.y = mcs.cy = CW_USEDEFAULT;
mcs.style = MDIS_ALLCHILDSTYLES;

hChild = (HWND)SendMessage(mdiClientWindow, WM_MDICREATE, 0, (LONG)&mcs);
DWORD dw = GetLastError();

if(!hChild)
{
char buffer[256];

FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,0,dw,MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),buffer,256,0);

MessageBox(hMain,buffer,"Error",MB_OK|MB_ICONERROR);
//MessageBox(hParent, "MDI Child creation failed.", "Oh Oh...", MB_ICONEXCLAMATION | MB_OK);
}

return hChild;
}




I can tell you definately that it returned an error. I actually knew what the error was before this, and GetLastError only reaffirmed it. Anyways, it shouldn't be telling you it completed successfully.

Also, another helpful hint.

[source]
Put your code in these blocks
[/source]
so it looks nice & formatted. Should be easier to read this way.

[Edited by - Nytegard on July 26, 2006 2:12:36 PM]

Share this post


Link to post
Share on other sites
I just cut and pasted your code over mine and I am still getting an error message stating "The Operation Completed Successfully". I still do not see the MDIChild window.

One thing that I did notice is that the error message is being displayed prior to the MDIParent being displayed. Looking through my code, I have asked for the MDIParent form to be displayed (ShowWindow(hParent, nCmdShow);) prior to creating the MDIChild (CreateNewMDIChild(mdiClientWindow);) I am not quite sure why that is.

Share this post


Link to post
Share on other sites
Quote:
Original post by CTEagle
I just cut and pasted your code over mine and I am still getting an error message stating "The Operation Completed Successfully". I still do not see the MDIChild window.

One thing that I did notice is that the error message is being displayed prior to the MDIParent being displayed. Looking through my code, I have asked for the MDIParent form to be displayed (ShowWindow(hParent, nCmdShow);) prior to creating the MDIChild (CreateNewMDIChild(mdiClientWindow);) I am not quite sure why that is.


Alright, I modified the code somewhat above. What compiler are you using BTW? The only reason I can think of that might be returning a success is if MS changed the SendMessage. It should be returning error 1407.

From MSDN
Quote:

Functions executed by the calling thread set this value by calling the SetLastError function. You should call the GetLastError function immediately when a function's return value indicates that such a call will return useful data. That is because some functions call SetLastError with a zero when they succeed, wiping out the error code set by the most recently failed function.


Anyways, why the message box is being displayed before the MDI window is the way Windows messaging works. Many windows functions, such as ShowWindow, are really only wrappers to messages that get pushed onto the message queue. Some messages will be pushed to the end of the queue, others will be called immediately and preempt the queue. Remember, just because you create a window, there are multiple messages that need to be processed before you can actually see the window.

*Quick Edit*

I'd also suggest looking up CreateMDIWindow on MSDN.

[Edited by - Nytegard on July 26, 2006 4:44:31 PM]

Share this post


Link to post
Share on other sites
Nytegard -

I am using VS2005.

Thanks for the information on my questions regarding when the messagebox gets displayed.

Any other thoughts on this problem would be greatly appreciated. I am off to read info on error 1407.

Share this post


Link to post
Share on other sites

LRESULT CALLBACK ChildProc(HWND hChild, UINT message, WPARAM wParam, LPARAM lParam)
{
// recursion!!!
return ChildProc(hChild, message, wParam, lParam);
}






should be instead:


LRESULT CALLBACK ChildProc(HWND hChild, UINT message, WPARAM wParam, LPARAM lParam)
{
return DefMDIChildProc(hChild, message, wParam, lParam);
}






then comment out your call to CreateNewMDIChild in your parent's (the frame window's) WM_CREATE message handler. this is not documented in MSDN, but you have to postpone creation of any children until after both calls to CreateWindow for the frame and the client have returned.

then uncomment out your call to CreateNewMDIChild that you have in WinMain right before you do your message loop and you'll see it works fine now (i tested it, the following adjusted code worked for me):


#undef UNICODE
#include <windows.h>
LRESULT CALLBACK WindowProc(HWND hMain, UINT message, WPARAM wParam, LPARAM lParam);
LRESULT CALLBACK ParentProc(HWND hParent, UINT message, WPARAM wParam, LPARAM lParam);
LRESULT CALLBACK ChildProc(HWND hChild, UINT msg, WPARAM wParam, LPARAM lParam);
HWND CreateNewMDIChild(HWND hMDIClient);
HWND hMain;
HWND hParent;
HWND hChild;
MSG msg;
HWND mdiClientWindow;
MDICREATESTRUCT mcs;

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow){

//This is a standard form

WNDCLASSEX frmMain;

frmMain.cbSize = sizeof(WNDCLASSEX);
frmMain.style = 0;
frmMain.cbClsExtra = 0;
frmMain.cbWndExtra = 0;
frmMain.hInstance = hInstance;
frmMain.hIcon = NULL;
frmMain.hCursor = LoadCursor(NULL, IDC_ARROW);
frmMain.hbrBackground = (HBRUSH)GetStockObject(LTGRAY_BRUSH);
frmMain.lpszMenuName = NULL;
frmMain.hIconSm = NULL;
frmMain.lpfnWndProc = WindowProc;
frmMain.lpszClassName = "frmMain";

if(!RegisterClassEx(&frmMain))
{
MessageBox(NULL, "Main Window Registration Failed!", "Error!",MB_ICONEXCLAMATION | MB_OK);
}

hMain = CreateWindowEx(WS_EX_CLIENTEDGE, "frmMain","frmMain",WS_SYSMENU,CW_USEDEFAULT, CW_USEDEFAULT, 480, 470,NULL, NULL, hInstance, NULL);

ShowWindow(hMain, nCmdShow);
UpdateWindow(hMain);

//This is a MDIParent
WNDCLASSEX frmParent;

frmParent.cbSize = sizeof(WNDCLASSEX);
frmParent.style = 0;
frmParent.cbClsExtra = 0;
frmParent.cbWndExtra = 0;
frmParent.hInstance = hInstance;
frmParent.hIcon = NULL;
frmParent.hCursor = LoadCursor(NULL, IDC_ARROW);
frmParent.hbrBackground = (HBRUSH)GetStockObject(LTGRAY_BRUSH);
frmParent.lpszMenuName = NULL;
frmParent.hIconSm = NULL;
frmParent.lpfnWndProc = ParentProc;
frmParent.lpszClassName = "frmParent";

if(!RegisterClassEx(&frmParent))
{
MessageBox(NULL, "frmParent Window Registration Failed!", "Error!",MB_ICONEXCLAMATION | MB_OK);
}

hParent = CreateWindowEx(WS_EX_CLIENTEDGE, "frmParent", "frmParent",WS_SYSMENU,CW_USEDEFAULT, CW_USEDEFAULT, 480, 470,NULL, NULL, hInstance, NULL);

ShowWindow(hParent, nCmdShow);
UpdateWindow(hParent);

//This is a MDIChild
WNDCLASSEX frmChild;

frmChild.cbSize = sizeof(WNDCLASSEX);
frmChild.style = 0;
frmChild.cbClsExtra = 0;
frmChild.cbWndExtra = 0;
frmChild.hInstance = hInstance;
frmChild.hIcon = NULL;
frmChild.hCursor = LoadCursor(NULL, IDC_ARROW);
frmChild.hbrBackground = (HBRUSH)GetStockObject(LTGRAY_BRUSH);
frmChild.lpszMenuName = NULL;
frmChild.hIconSm = NULL;
frmChild.lpfnWndProc = ChildProc;
frmChild.lpszClassName = "frmChild";

if(!RegisterClassEx(&frmChild))
{
MessageBox(NULL, "frmChild Window Registration Failed!", "Error!",MB_ICONEXCLAMATION | MB_OK);
}

// changed this
CreateNewMDIChild(mdiClientWindow);

while(GetMessage(&msg, 0,0,0)== TRUE)
{
// changed this
if(!TranslateMDISysAccel(mdiClientWindow, &msg)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return 0;
}

LRESULT CALLBACK WindowProc(HWND hMain, UINT message, WPARAM wParam, LPARAM lParam)
{
switch(message)
{

case WM_DESTROY:
PostQuitMessage(0);
return 0;

default:
return DefWindowProc(hMain, message, wParam, lParam);
}
}

LRESULT CALLBACK ParentProc(HWND hParent, UINT message, WPARAM wParam, LPARAM lParam)
{
switch(message)
{
case WM_CREATE:
{

CLIENTCREATESTRUCT ccs;

ccs.hWindowMenu = 0;
ccs.idFirstChild = 5000;
mdiClientWindow = CreateWindowEx(WS_EX_CLIENTEDGE, "mdiclient", NULL, WS_CHILD | WS_CLIPCHILDREN | WS_VSCROLL | WS_HSCROLL | WS_VISIBLE,
0, 0, 0, 0, hParent, 0, GetModuleHandle(NULL), (LPVOID)&ccs);
// changed this
//CreateNewMDIChild(mdiClientWindow);

return 0;
}
case WM_DESTROY:
{
PostQuitMessage(0);
return 0;
}

default:

return DefFrameProc(hParent, mdiClientWindow, message, wParam, lParam);
}
}

LRESULT CALLBACK ChildProc(HWND hChild, UINT message, WPARAM wParam, LPARAM lParam)
{
return DefMDIChildProc(hChild, message, wParam, lParam); // changed this
}

HWND CreateNewMDIChild(HWND mdiClientWindow)
{
mcs.szTitle = "Child Form";
mcs.szClass = "frmChild";
mcs.hOwner = GetModuleHandle(NULL);
mcs.x = mcs.cx = CW_USEDEFAULT;
mcs.y = mcs.cy = CW_USEDEFAULT;
mcs.style = MDIS_ALLCHILDSTYLES;

hChild = (HWND)SendMessage(mdiClientWindow, WM_MDICREATE, 0, (LONG)&mcs);
if(!hChild)
{
MessageBox(hParent, "MDI Child creation failed.", "Oh Oh...", MB_ICONEXCLAMATION | MB_OK);
}

return hChild;
}



Share this post


Link to post
Share on other sites
Thanks Nytegard and Yadango for all of your help. The final bits that Yadango corrected the problem I was having.

I would like some clarification on something that Yadango mentioned. Yadango stated that:

"this is not documented in MSDN, but you have to postpone creation of any children until after both calls to CreateWindow for the frame and the client have returned."

When you refer to "the frame" are you referring to "hParent" in my code?
When you refer to "the client" are you referring to "mdiClientWindow" in my code?

Thanks.

[Edited by - CTEagle on July 27, 2006 8:21:06 AM]

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!