-
January 25th, 2002, 10:06 AM
#1
Message to Parent Dialog produces Crash in Release Version
Hi
From a MainDlg I dynamically create a SubDlg for showing sort of a work progress. At the end the user can close the SubDlg.
In OnClose I post/send a message to the MainDlg to indicate that the SubDlg closes. The MainDlg does some clean-up work then and the SubDlg closes and deletes itself.
Problem: this all workes well compiled as Debug Version, but crashes when compiled as Release (no matter whether MFC used statically or dynamically).
Where is the crash: When posting/sending the message from the SubDlg to the Parent (MainDlg, the MainDlg exeutes the clean-up work (OnMessageCleanUp), but if the execution returns to where the message was sent/posted and wants to continue, it crashes before the next line in the SubDlg is executed.
When I do not send/post a message and call the appropriate function (declared as public) directly from within SubDlg and its parent member, there's no problem.
The code looks as follows:
#if !defined(AFX_MAINDLG_H__27D8CA5A_A1E7_4549_9735_C4DD57694768__INCLUDED_)
#define AFX_MAINDLG_H__27D8CA5A_A1E7_4549_9735_C4DD57694768__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
// MainDlg.h : header file
//
// Include for the udownloader interfaces
#include "SubDlg.h"
/////////////////////////////////////////////////////////////////////////////
// CMainDlg dialog
class CMainDlg : public CDialog
{
// Construction
public:
// CMutex m_mutexCloseProgressDlg;
void AbortDownload(BOOL bAbort = TRUE) { m_bAbortDownload = bAbort; }
CMainDlg(CWnd* pParent = NULL); // standard constructor
virtual ~CMainDlg();
// Dialog Data
//{{AFX_DATA(CMainDlg)
enum { IDD = IDD_CFGMGR_DIALOG };
//}}AFX_DATA
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CMainDlg)
//}}AFX_VIRTUAL
// Implementation
protected:
HICON m_hIcon;
// Generated message map functions
//{{AFX_MSG(CMainDlg)
virtual BOOL OnInitDialog();
afx_msg void OnPaint();
afx_msg HCURSOR OnQueryDragIcon();
afx_msg void OnClose();
afx_msg void OnDestroy();
afx_msg void OnBtnDownload();
//}}AFX_MSG
afx_msg void EndDownloadThread();
DECLARE_MESSAGE_MAP()
public:
afx_msg void OnCloseSubDlg();
private:
BOOL m_bAbortDownload;
CSubDlg* m_pProgressDlg;
HANDLE m_hDownloadThread;
};
//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
#endif // !defined(AFX_MAINDLG_H__27D8CA5A_A1E7_4549_9735_C4DD57694768__INCLUDED_)
// MainDlg.cpp : implementation file
//
#include "StdAfx.h"
#include "Main.h"
#include "MainDlg.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CMainDlg Download Thread
DWORD WINAPI DownloadThread(LPVOID pVoid)
{
CMainDlg* pParent = reinterpret_cast<CMainDlg*>(pVoid);
// pParent->MessageBox(_T("Start Download"));
Sleep(1000);
// pParent->MessageBox(_T("End Download"));
pParent->PostMessage(EV_END_DOWNLOAD_THREAD);
return 0;
} // DownloadThread(LPVOID pVoid)
/////////////////////////////////////////////////////////////////////////////
// CMainDlg dialog
CMainDlg::CMainDlg(CWnd* pParent /*=NULL*/)
: CDialog(CMainDlg::IDD, pParent),
m_pProgressDlg(NULL), m_hDownloadThread(NULL), m_bAbortDownload(FALSE)
{
// Note that LoadIcon does not require a subsequent DestroyIcon in Win32
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
} // CMainDlg::CMainDlg(CWnd* pParent /*=NULL*/)
CMainDlg::~CMainDlg()
{
} // CMainDlg::~CMainDlg()
BEGIN_MESSAGE_MAP(CMainDlg, CDialog)
//{{AFX_MSG_MAP(CMainDlg)
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_BN_CLICKED(IDC_BTN_CLOSE, OnClose)
ON_WM_DESTROY()
ON_BN_CLICKED(IDC_BTN_DOWNLOAD, OnBtnDownload)
//}}AFX_MSG_MAP
ON_MESSAGE(EV_CLOSE_PROGRESS_DIALOG, OnCloseSubDlg)
ON_MESSAGE(EV_END_DOWNLOAD_THREAD, EndDownloadThread)
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CMainDlg message handlers
BOOL CMainDlg::OnInitDialog()
{
CDialog::OnInitDialog();
// Set the icon for this dialog. The framework does this automatically
// when the application's main window is not a dialog
SetIcon(m_hIcon, TRUE); // Set big icon
SetIcon(m_hIcon, FALSE); // Set small icon
SIZE sizeDisplay;
sizeDisplay.cx = GetSystemMetrics(SM_CXFULLSCREEN)/2;
sizeDisplay.cy = GetSystemMetrics(SM_CYFULLSCREEN)/2;
// Because LoadData() uses SetRedraw function, the taskbar icon is not displayed
// This is fixed with the call of ShowWindow(SW_HIDE).
ShowWindow(SW_HIDE);
CRect rc;
GetWindowRect(&rc);
long lWidth = rc.Width();
long lHeight = rc.Height();
rc.left = sizeDisplay.cx - (lWidth / 2);
rc.top = sizeDisplay.cy - (lHeight / 2);
SetWindowPos(&wndTop, rc.left, rc.top, lWidth, lHeight, NULL);
return TRUE; // return TRUE unless you set the focus to a control
}
// If you add a minimize button to your dialog, you will need the code below
// to draw the icon. For MFC applications using the document/view model,
// this is automatically done for you by the framework.
void CMainDlg::OnPaint()
{
if (IsIconic())
{
CPaintDC dc(this); // device context for painting
SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);
// Center icon in client rectangle
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;
// Draw the icon
dc.DrawIcon(x, y, m_hIcon);
}
else
CDialog::OnPaint();
} // CMainDlg::OnPaint()
// The system calls this to obtain the cursor to display while the user drags
// the minimized window.
HCURSOR CMainDlg::OnQueryDragIcon()
{
return (HCURSOR) m_hIcon;
}
void CMainDlg::OnClose()
{
if (NULL != m_pProgressDlg)
{
// m_pProgressDlg->DestroyWindow();
// delete m_pProgressDlg;
m_pProgressDlg = NULL;
} // if (NULL != m_pProgressDlg)
OnOK();
} // CMainDlg::OnClose
void CMainDlg::OnDestroy()
{
CDialog::OnDestroy();
} // CMainDlg::OnDestroy()
void CMainDlg::OnBtnDownload()
{
// Check at the very beginning of Download, if the DownloadThread is still running
if (NULL != m_hDownloadThread)
{
EndDownloadThread();
} // if (NULL != m_hDownloadThread)
// Now that it's sure that the thread doesn't run, create the dialog and start the thread
m_pProgressDlg = new CSubDlg;
if (!m_pProgressDlg->Create(IDD_PROGRESS_DIALOG, this))
m_pProgressDlg = NULL;
EnableWindow(FALSE);
m_pProgressDlg->ShowWindow(SW_SHOW);
m_hDownloadThread = CreateThread(NULL, 0, &DownloadThread, (LPVOID)this, CREATE_SUSPENDED, NULL);
if (NULL == m_hDownloadThread)
{
CString str;
str.Format(_T("Error #%d: Could not initiate Download"), GetLastError());
MessageBox(str, _T("Error"), MB_ICONSTOP);
CloseHandle(m_hDownloadThread);
m_hDownloadThread = NULL;
m_pProgressDlg->DestroyWindow();
delete m_pProgressDlg;
m_pProgressDlg = NULL;
EnableWindow(TRUE);
return;
} // if
ResumeThread(m_hDownloadThread);
} // CMainDlg::OnBtnDownload()
void CMainDlg::OnCloseSubDlg()
{
MessageBox(_T("OnCloseSubDlg"));
// The SubDlg destroys and deletes itself.
// m_pProgressDlg->DestroyWindow();
// delete m_pProgressDlg;
MessageBox(_T("ProgressDlg = NULL"));
m_pProgressDlg = NULL;
EnableWindow(TRUE);
MessageBox(_T("Window enabled"));
} // CMainDlg::OnCloseSubDlg()
void CMainDlg::EndDownloadThread()
{
WaitForSingleObject(m_hDownloadThread, INFINITE);
CloseHandle(m_hDownloadThread);
m_hDownloadThread = NULL;
if (NULL != m_pProgressDlg)
m_pProgressDlg->SetAbortToClose();
} // CMainDlg::EndDownloadThread()
#if !defined(AFX_SUBDLG_H__30FDA0CE_7240_4C42_A779_7B593F2CC756__INCLUDED_)
#define AFX_SUBDLG_H__30FDA0CE_7240_4C42_A779_7B593F2CC756__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
// SubDlg.h : header file
//
/////////////////////////////////////////////////////////////////////////////
// CSubDlg dialog
class CSubDlg : public CDialog
{
// Construction
public:
void SetAbortToClose();
CSubDlg(CWnd* pParent = NULL); // standard constructor
// Dialog Data
//{{AFX_DATA(CSubDlg)
enum { IDD = IDD_PROGRESS_DIALOG };
//}}AFX_DATA
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CSubDlg)
protected:
virtual void PostNcDestroy();
//}}AFX_VIRTUAL
// Implementation
protected:
// Generated message map functions
//{{AFX_MSG(CSubDlg)
virtual void OnCancel();
virtual BOOL OnInitDialog();
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
private:
BOOL m_bCloseNextTime;
BOOL m_bIsClosed;
};
//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
#endif // !defined(AFX_SUBDLG_H__30FDA0CE_7240_4C42_A779_7B593F2CC756__INCLUDED_)
// SubDlg.cpp : implementation file
//
#include "StdAfx.h"
#include "Main.h"
#include "MainDlg.h"
#include "SubDlg.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CSubDlg dialog
CSubDlg::CSubDlg(CWnd* pParent /*=NULL*/)
: CDialog(CSubDlg::IDD, pParent), m_bCloseNextTime(FALSE), m_bIsClosed(FALSE)
{}
BEGIN_MESSAGE_MAP(CSubDlg, CDialog)
//{{AFX_MSG_MAP(CSubDlg)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CSubDlg message handlers
void CSubDlg::OnCancel()
{
if (!m_bCloseNextTime)
{
AfxGetApp()->LoadStandardCursor(IDC_WAIT);
((CMainDlg*)GetParent())->AbortDownload(TRUE);
} // if (m_bCloseNextTime)
else
{
m_bIsClosed = TRUE;
ShowWindow(SW_HIDE);
MessageBox(_T("Posting Message"));
// Send message doesn't work in Release Version (Debug okay)
((CMainDlg*)GetParent())->SendMessage(EV_CLOSE_PROGRESS_DIALOG);
// Direct call works in both versions (Debug and Release)
// ((CMainDlg*)GetParent())->OnCloseSubDlg();
MessageBox(_T("Message Posted"));
DestroyWindow();
} // else
} // CSubDlg::OnCancel()
void CSubDlg::SetAbortToClose()
{
MessageBeep(MB_OK);
m_bCloseNextTime = TRUE;
m_bIsClosed = FALSE;
GetDlgItem(IDCANCEL)->SetWindowText(_T("&Close"));
AfxGetApp()->LoadStandardCursor(IDC_ARROW);
} // CSubDlg::SetAbortToClose()
BOOL CSubDlg::OnInitDialog()
{
CDialog::OnInitDialog();
CRect rc;
GetWindowRect(&rc);
long lWidth = rc.Width();
long lHeight = rc.Height();
CRect rcParent;
((CMainDlg*)GetParent())->GetWindowRect(&rcParent);
long lParentWidth = rcParent.Width();
long lParentHeight = rcParent.Height();
rc.left = rcParent.left + ((lParentWidth - lWidth) / 2);
rc.top = rcParent.top + ((lParentHeight - lHeight) / 2);
SetWindowPos(NULL, rc.left, rc.top, lWidth, lHeight, NULL);
return TRUE; // return TRUE unless you set the focus to a control
// EXCEPTION: OCX Property Pages should return FALSE
} // CSubDlg::OnInitDialog()
void CSubDlg::PostNcDestroy()
{
delete this;
} // CSubDlg::PostNcDestroy()
Any suggestions, why the Send-/Post-Message doesn't work here? Is this a bug?
Many thanks for helping to solve this problem.
(previous/related thread: http://www.codeguru.com/cgi-bin/bbs/...sb=5&category=)
I do what I can to help - at least.
And I really appreciate every help, as well!
Ratings are always welcome - I give, too.
-
January 25th, 2002, 10:25 AM
#2
Re: Message to Parent Dialog produces Crash in Release Version
You are declaring two functions:
void OnCloseSubDlg();
void EndDownloadThread();
You use this function as messages handlers by using ON_MESSAGE macro.
If you look into the MSDN, you will find out, that prototype of such message handlers has to be:
LRESULT OnSomeMessagFnc(WPARAM wParam, LPARAM lParam);
I thing, this is the cause of the crash!
Martin
-
January 25th, 2002, 11:11 AM
#3
Re: Message to Parent Dialog produces Crash in Release Version
Thanks, this really solves the problem. But the question that stays is WHY?
I used ON_MESSAGE already so many times and had no problem with it. Also it's not comprehensive to me that it works in Debug version but not in Release version. Do you know these answers?
Thanks
Holi
I do what I can to help - at least.
And I really appreciate every help, as well!
Ratings are always welcome - I give, too.
-
January 25th, 2002, 11:44 AM
#4
Re: Message to Parent Dialog produces Crash in Release Version
Yes sure.
Macro makes call of function which returns LRESULT and which have two parameters.
You write just "void" function.
Code generated by ON_MESSAGE macro puts WPARAM and LPARAM onto the stack before calling message handler and wants to get return value.
Hoverver, parameters as well as return value are not supported by the function and it has to cause crash!
Martin
-
January 28th, 2002, 05:07 AM
#5
Re: Message to Parent Dialog produces Crash in Release Version
Hi Martin
I have a new strange effect now: when closing the SubDlg, the MainDlg disappears behind the next other app (in z-order) that's open. When closing the SubDlg, OnCloseSubDlg() is called, where I enable the MainDlg again. Maybe it's because of that?
When I call ShowWindow(SW_HIDE) and ShowWindow(SW_SHOW) after Enabling the window, the MainDlg shows up again. Calling ShowWindow(SW_SHOW) only doesn't work.
Any idea? Thanks.
Holi
I do what I can to help - at least.
And I really appreciate every help, as well!
Ratings are always welcome - I give, too.
-
January 30th, 2002, 08:29 PM
#6
Re: Message to Parent Dialog produces Crash in Release Version
Thank you. I had the very same problem in my code. The fact it worked in the Debug version, but not the Release really threw me off. Much appreciated.
Daniel
-
March 15th, 2002, 01:38 PM
#7
Re: Message to Parent Dialog produces Crash in Release Version
Hi
I also have the same problem. User defined message works fine in debug mode but crashes in release version. But the problem is solved by changing the prototype of message handler as you told in the post. But i did not understand why this happens. Why it does not crash in debug mode also...
Thanks
Shashi
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|