RESOLVED - MDI Child Creation Problem

Started by
8 comments, last by yadango 17 years, 8 months ago
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]
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>
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?
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]
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.
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]
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.
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;}
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]
correct you are sir.

This topic is closed to new replies.

Advertisement