Click here to Skip to main content
15,921,716 members
Please Sign up or sign in to vote.
5.00/5 (1 vote)
See more:
I am a newbie to MFC and C++.

Some background info:
I am creating a tool to display graphs across 7 dialogs. I am creating the parent dialog as a modal type and in its OnInitDialog(), i am creating 6 different modeless dialogs (one parent, multiple child). Following is the code that i am using to create 1 modeless dialog:

C#
nbiq_dlg2 = new nbiq_dialog2(this);
if (TRUE == nbiq_dlg2->Create())
{
    nbiq_dlg2->ShowWindow(true);
}


I am using the similar method given in a sample project by MSDN to create and destroy the modeless dialogs:
http://msdn.microsoft.com/en-us/library/zhk0y9cw%28VS.80%29.aspx[^]

My application does not expect any input from the user and thus has no buttons. I am making sure that when the main dialog is closed, all the child dialogs are destroyed if they are already not.

Problem:
However when i run this program, everything is fine until i start closing the dialogs. 4 out of 5 times, the application crashes and when i press "Debug", it gives the following error:

The instruction at "0x00000000" referenced at "0x00000000". The memory could not be read.


During debug mode, i get this error when i close any of the dialogs "first chance exception in test.exe: 0xc0000005: access violation" and
C#
this    CXX0017: Error: symbol "this" not found


Again, this does not happen every time.

I have been debugging this issue for over a week and i am still not able to figure out the fault. Any insights/ideas would be most helpful.

Thanks,
Hari
Posted

Try this sequence to open a child :
{
  if (!m_pcChild) {
    m_pcChild = new ..;
  }
  if (!m_pcChild->GetSafeHwnd()) {
    m_pcChild->Create(..);
  }
  if (m_pcChild->GetSafeHwnd()) {
    m_pcChild->ShowWindow(SW_SHOW);
  }
}
...to hide it:
{
  if (m_pcChild->GetSafeHwnd()) {
    m_pcChild->ShowWindow(SW_HIDE);
  }
}
...and to destroy it :) :
{
  if (m_pcChild->GetSafeHwnd()) {
    m_pcChild->DestroyWindow();
  }
  if (m_pcChild) {
    delete m_pcChild;
  }
  m_pcChild = NULL; // the same line should be placed
                    // in the constructor of your parent 
}
 
Share this answer
 
R u using this inside a static function???
 
Share this answer
 
No. I am not using static functions. Since i am new to this, does it make a difference?

Hari
 
Share this answer
 
Hi Eugen.

I tried what you said but the problem still exists. Sometimes i am able to close the application properly without crashing. Other times, it crashes even if i close 1 dialog. Sometimes, the application works fine when i close 2-3 dialogs. When i close the 4th one, its gone.

I guess i am not passing the control properly to the parent window when i close the child dialog.

The MSDN article that i had mentioned earlier said that i should override the default the PostNCDestroy() and do delete this; inside that function.

Every time the application crashes, it says the following:

Debug assertion failed!

Program: C:\proj\test2.exe
File: cmdtarg.cpp
Line: 52


This is the part of the 'cmdtarg.cpp' which generates the above error:

CCmdTarget::~CCmdTarget()
{
#ifndef _AFX_NO_OLE_SUPPORT
	if (m_xDispatch.m_vtbl != 0)
		((COleDispatchImpl*)&m_xDispatch)->Disconnect();
	ASSERT(m_dwRef <= 1);
#endif
#ifdef _AFXDLL
	m_pModuleState = NULL;
#endif
}



Hari
 
Share this answer
 
v2
Hm... delete this; would not set the dialog pointer to NULL in the parent object... :)

1. Test Solution:
- the WM_CLOSE reaction function of each child -
does ShowWindow(SW_HIDE) only
- the destroying and deleting of the child (last block of my last posting)
will be processed at the CYourParentDlg::OnDestroy() only

2. Test Solution:
- the parent has the instances (not the pointers) of all 6 children
- the all kinds of the parent-child communication
are protected by if (m_cXXChild.GetSafeHwnd()) {..}
- the WM_CLOSE reaction function of each child -
calls the public void CYourParentDlg::DestroyMePlease(CWnd* pcWndToDestroy) with this parameter only
{
  if (pcWndToDestroy->GetSafeHwnd()) {
    pcWndToDestroy->DestroyWindow();
  }
}


Firstly I have understood
there is the problem at the parent's closing only, sorry.

Good luck :)
 
Share this answer
 
v2
Hi Eugen.

I am still unsure about the solution. Here is the snippet of what i have done:


OnClose function of child window:


C#
void child_window::OnClose()
{
    ((parent_window*)m_pParent)->DestroyChildWindow();
}


C#
void parent_window::DestroyChildWindow()
{
    if (my_child->GetSafeHwnd())
    {
        my_child->DestroyWindow();
    }
    if (my_child)
    {
        delete my_child;
    }
    my_child = NULL;

    EnableWindow(true);
}


OnClose function of parent window:
MIDL
void parent_window::OnClose()
{
    /*
     * destroy the child dialog if it is not already destoyed
     */
    if (NULL != my_child)
    {
        DestroyChildWindow();
    }
    CDialog::OnClose();
}


I have created the child windows as you had suggested using GetSafeHwnd()

Hari
 
Share this answer
 
Hi Hari,

the first solution (?) could be easier,
when you will want to stay by the "pointers" form:
void CChild::OnClose()
{
  ShowWindow(SW_HIDE);
}

void CParent::OnDestroy()
{
  if (m_pcChild) {
    if (m_pcChild->GetSafeHwnd()) {
      m_pcChild->DestroyWindow();
    }
    delete m_pcChild;
    m_pcChild = NULL;
  }
  // the same blocks for other children
  // ... 
} 


In your current solution
you will need a personal DestroyXXChild() for each child in your parent...
If you will want to go to the "instances" form,
you could implement an universal function:
void CParent::DestroyPassedChild(CWnd* pcChild)
{
  if (pcChild->GetSafeHwnd()) {
    pcChild->DestroyWindow();
  }
}

...that could be called by some child:
void CChild::OnClose()
{
  if (m_pcParent) {
    ((CParent*) m_pcParent)->DestroyPassedChild(this);
  }
}


Are your failed assertions gone ? :)
 
Share this answer
 
v3
Hi Eugen.

I have implemented a combination of the two solutions that you have suggested. On closing the child window, i don't destroy it immediately. Instead, i hide it using

C#
void CChild::OnClose()
{
  ShowWindow(SW_HIDE);
}


I have implemented the OnDestroy function of the parent as follows:

C#
void parent_window::OnDestroy()
{
    if (NULL != my_child1)
    {
        DestroyChildWindowChild1();
    }
    //same for the remaining 5 child windows

    CDialog::OnDestroy();
}


I have implemented a DestroyChild() for each child. However the problem still exists. When i close the parent window, I am still getting the "debug assertion failed error". :( :confused:

Is it okay if i destroy one child window after the other? I mean i am calling DestroyChild() continuously for 6 times (one for each child) and then finally, i call CDialog::OnDestroy(); to destroy the parent window. Am i missing some handling of pointers or something?

I am sure that the problem is because i am destroying the windows one after the other. I don't see any issues if i have only one child. I also tried the architecture where one parent has only one child and the child itself acts as a parent for the next one (something like an hierarchy). I end with the same issues.

I also have one more question. Does the order in which i destroy the child windows matter? I mean if i created the child windows 1 to 6 in sequence, should i destroy them in the same sequence?

Hari
 
Share this answer
 
v2
Comments
Eugen Podsypalnikov 27-Jul-10 18:05pm    
You can destroy and delete them in any order :)
OK... :)

0.) Please delete any overwritten PostNCDestroy() (if any)
1.) Test one more
2.) If you will meet the failed assertions again -
please set the breakpoints in all destructors of your children
and count the calls for each destructor (schould be one per object).
Please analyse or post here the call stacks for a double call of them.
 
Share this answer
 
I have removed the overwritten PostNCDestroy() but the problem is still there. But now, its better than before. It crashes, probably, 1 out of 5 times.

I don't have any destructors for the child windows. I am assuming that the default destructors will be called when it is destroyed.

Hari
 
Share this answer
 
v2
Hi Hari,

I have inspected my code of an analog task
and found some diferences (compared to my words "in the past")... :-O :)

Neither the parent context nor the child call DestroyWindow()...
Instead the function EndDialog(IDCANCEL) will be used for each child there...

Please observe my fragments below:
C++
CProfileEngine::CProfileEngine(CProjektRT* pcProjekt)
{
  SetProjekt(pcProjekt);
  m_cszLastUserRef = USER_TITEL_SYS;
  m_pcDialog = NULL; // Initialization at the parent's constructor

  ResetReception();
}

Since my parent is not a window, I have the the clearance at its destructor,
your correct place would be probably CParentDlg::OnDestroy() :
C++
CProfileEngine::~CProfileEngine()
{
  if (m_pcDialog) {
    if (m_pcDialog->GetSafeHwnd()) {
      m_pcDialog->EndDialog(IDCANCEL); // "Destroying" (!!)
    }
    delete m_pcDialog;
  }
}

Here is the activation stage:
C++
void CProfileEngine::Administrate()
{
  if (!m_pcDialog) {
    m_pcDialog = new CProfileDlg(this, ::AfxGetMainWnd()); // Child's allocation
  }
  if (m_pcDialog && !m_pcDialog->m_hWnd) {
    if (m_pcDialog->Create(CProfileDlg::IDD, ::AfxGetMainWnd())) { // Child's creation
      // May be a style tuning...
    }
  }
  if (m_pcDialog && m_pcDialog->m_hWnd) {
    m_pcDialog->ShowWindow(SW_SHOW); // Child's activation
    m_pcDialog->SetFocus();
  }
}

And the closing reaction of the child (maybe you do not need it generally):
C++
void CProfileDlg::OnCloseBox()
{
  CD_CTranslateDlg::OnCancel(); // The base canceling (your base is CDialog) 
}

Please try to replace all children's DestroyWindow() by EndDialog(IDCANCEL).

Sorry - for my complicated prelude :)
 
Share this answer
 
Hi Eugen.

I guess EndDialog() did the trick. My application seems to be stable now.

However, my application crashes when i run it for the first time through the IDE. Subsequently, it is working fine. I read in some forum that this behavior is quite normal while having child windows. I am not able to remember the exact details though. You have any thoughts on that?

Anyways, thanks for all your help. I have learnt a lot thought this process. :) :)

Hari
 
Share this answer
 
v2
Hi Hari,

no, I would not write that this crash is quite normal...

You could build a Debug version and start it by F5,
then, after an exception or an failed assertion is shown, press "Retry" -

to see the crash line (it could be a MFC or even OS DLL line), then -
select the menu item Debug->Windows->Call Stack

to see the calls history of the crash, then -
find the first line of your code from the stack's top,

process a double click on your line there,
now you are in _your_ crash context,

you can observe the values of the variables (tool tips at the mouse cursor),
or open the QuickWatch window (right mouse click) to analyse the crash causing

(it could be a wrong pointer, or a message at a not created window...)

You could post here your call stacks as well... :)
 
Share this answer
 
Hi Eugen.

As you said, i am trying to catch the exception in debug mode but i am not able to do so. What i mean to say is that the exception is not repeatable/reproducible.

Anyways, if i do catch it, i will post the necessary information here.

Thanks,
Hari
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900