I've added new dialogs and pieces to my wxApp, but now when I close the main frame, the main frame get deleted but it never get to the OnExit function, and is stuck.
When I try to "break all", it get in this function call:
wxIdleWakeUpModule::MsgHookProc
in:
return CallNextHookEx(ms_hMsgHookProc, nCode, wParam, lParam);
Do you have any advice on how to fix that ?
Use Destroy when dialog is closed. This page shows how to do that when creating an object on heap:
void AskUser()
{
MyAskDialog *dlg = new MyAskDialog(...);
if ( dlg->ShowModal() == wxID_OK )
...
//else: dialog was cancelled or some another button pressed
dlg->Destroy();
}
When the dialog is created on the stack you shouldn't do anything special.
So after I've tested one by one all the pieces of code I've added to my previously working program, I've realized that one of the wxDialog I was creating had no parent, but this was not intended.
So because of that it would not close because one of the main window was still alive (even though it was not shown)
Thanks all for your help
Related
I am working on an MFC application(VS2017).
In that I have a made one second timer. Inside the OnTimer() routine along with my business logic I am calling UpdateData(FALSE) to show some runtime info back to UI.
Also, I have to get some user input from the UI for that inside the user Input Event handler, I am calling UpdateData(TRUE) and checking its return value in OnTimer routine.
Problem is since the timer is an independent entity here. Even though I have guarded the UpdateData(FALSE) inside OnTimer the UpdateData(FALSE) is getting executed for a blank user input, which crashes the program by calling assert.
/***SAMPLE Problem CODE****/`
void abc::OnEnUserInput()
{
IsvalidInput = UpdateData(TRUE);
}
void abc::OnTimer(UINT_PTR nIDEvent)
{
if (IsvalidInput == true)
{
UpdateData(FALSE);
}
}
Any help would be greatly appreciated!!!
Thanks.
Got my solution earlier itself but due to the busy schedule couldn't get time to share it.
for avoiding this issue I opened another dialogue box to receive the user input, since UpdatedData(FALSE) in OnTimer() is in background dialogue box so the user input in child dialog UpdateData(TRUE) will not interfare with background UpdatedData(FALSE).
I have seen a similar question here:
How to close a modeless MFC dialog in C++
This is how I close my modeless dialogue:
void CChristianLifeMinistryEditorDlg::OnDestroy()
{
if (m_pAssignHistoryDlg != NULL)
{
delete m_pAssignHistoryDlg;
m_pAssignHistoryDlg = NULL;
}
CDialogEx::OnDestroy();
}
This has always been sufficient, until today. What I have found out (quote by chance) is that if the modeless dialogue has a message box up, and the user goes and closes the parent dialogue, the modeless dialogue stays on screen until you close the message box.
The modelless dialogue is clearly still within an event handler since it has just performed some action and displayed the results to the user.
Is it possible to force it to shut? Or should I somehow stop my parent dialogue from being closed whilst the modelless popup is on screen?
What is the right thing to do?
Thank you.
Update:
I tried this:
void CChristianLifeMinistryEditorDlg::OnDestroy()
{
if (m_pAssignHistoryDlg != NULL)
{
CWnd *pPopupMessage = m_pAssignHistoryDlg->GetWindow(GW_ENABLEDPOPUP);
if (pPopupMessage != NULL)
pPopupMessage->PostMessage(WM_CLOSE);
delete m_pAssignHistoryDlg;
m_pAssignHistoryDlg = NULL;
}
CDialogEx::OnDestroy();
}
It didn't work. When I debugged, it refused to process that call etc until I had dismissed the popup message box myself.
Things are further complicated by the fact the the modelless dialogue makes use of two message boxes:
Are you sure you want to delete the name? YES | NO
Name deleted OK
Either the code can be changed to work, or if I go the custom message route I need to know the result of the message box before my code can proceed (for scenario 1).
Update 2:
I am now confused. I added a custom registered message in the parent dialogue:
afx_msg LRESULT CChristianLifeMinistryEditorDlg::OnDisplayMessage(WPARAM wParam, LPARAM lParam)
{
return AfxMessageBox((LPCTSTR)wParam, (UINT)lParam);
}
The modeless dialogue invokes it like this:
iResult = ::SendMessage(GetParent()->GetSafeHwnd(), UWM_DISPLAY_MESSAGE_MSG,
(WPARAM)strEntry.GetBuffer(_MAX_PATH), MB_YESNO | MB_ICONQUESTION);
strEntry.ReleaseBuffer();
I have placed a breakpoint in the message handler so I know it is being fired correctly. And indeed a message box is being displayed.
But for some reason, the message box is still showing central to the modeless dialogue and not the editor. I don't understand why?
Result!
I found this topic: How to force AfxMessageBox to center on mainframe and not whatever child window that currently has focus
I adjusted my code:
afx_msg LRESULT CChristianLifeMinistryEditorDlg::OnDisplayMessage(WPARAM wParam, LPARAM lParam)
{
return MessageBox((LPCTSTR)wParam, NULL, (UINT)lParam);
}
Now it shows center of the parent dialogue.
I do apologize that this question started of in one direction and ended up with an answer in another direction. I am not sure what we do about that? Technically, the comment to me to use GetWindow didn't seem to work for me. So as such, there is no answer. But by changing my design I have been able to prevent the situation.
Premature Result
Whilst the message box showed centered, it affects the subsequent code. Coming up with read allocation errors.
But I have come up with a viable solution now:
GetParent()->EnableWindow(FALSE);
strEntry.Format(IDS_TPL_SURE_DELETE_FROM_ASSIGN_HIST, psHist->strName);
if (AfxMessageBox(strEntry, MB_YESNO | MB_ICONQUESTION) == IDNO)
{
GetParent()->EnableWindow(TRUE);
return;
}
I disable the parent before showing the message box and enable it again once it is dismissed. This prevents the user from closing the main window. They much close the popup message. I will have to go this way for now.
Thanks guys.
I'm trying to close dialog box (which is basically derived from propertysheet class) from code. following is my code:
LRESULT CSettingsSheet::OnCloseSettings(WPARAM wParam, LPARAM lParam)
{
EndDialog(IDCANCEL);
return 0;
}
the issue is endDialog terminates not only dialog box but also main application window. what could be the reason for this problem?
BTW i create this dialog box in main window as follow
if(settingsSheet.DoModal() == IDOK)
{
}
else
{
}
ideally i should set this domodal value with IDCANCEL instead of calling end dialog.
Thanks,
Khurram.
You need to send PSM_PRESSBUTTON message to the property sheet window:
Simulates the selection of a property sheet button. You can send this message explicitly or by using the PropSheet_PressButton macro.
PSBTN_CANCEL - Selects the Cancel button.
PSBTN_OK - Selects the OK button. This value is not valid when using the Aero wizard style (PSH_AEROWIZARD).
The MFC has a function for this CPropertySheet::PressButton.
I am creating my own subclass of wxDialog and it works well when used as a modeless dialog like so:
AddDialog newAddDialog = new AddDialog(this, wxID_ANY, _T("Dialog Title"), wxDefaultPosition, wxDefaultSize, 0);
if (newAddDialog.ShowModal() == wxID_OK)
{
//do something
}
When using ShowModal(), the flow of the program stops until OK or Cancel is pressed. I need the dialog to show up, but not stop the flow of the GUI, so I tried this:
AddDialog newAddDialog = new AddDialog(this, wxID_ANY, _T("Dialog Title"), wxDefaultPosition, wxDefaultSize, 0);
if (newAddDialog.Showl() == wxID_OK)
{
//do something
}
When using Show(), the dialog briefly shows up and then disappears. I thought it might be a scope issue, so I used a pointer for newAddDialog. Then, the dialog shows up, when when I click OK or Cancel, the dialog closes, but the if statement code does not execute even if OK is clicked.
Does anyone know how to proceed? Thanks.
Further clarification:
I have virtual void function in my Dialog subclass that I overide in another class. I can't seem to get the event working when I overide, however, if I have a void in the actual Dialog subclass, I get the event call. This seems to be an overide problem, but I don't know what the problem would be. This is not the main GUI that I'm calling in the OnInit() call - could that be a problem?
ShowModal blocks execution of your program and returns the outcome (like wxID_OK). On the other hand, Show just shows the dialog and returns immediately, so you can't check the outcome (what the user pressed for buttons) from it's return value. Instead you have to communicate the outcome of that dialog-box by sending an event from withing the dialog or something like that.
AddDialog newAddDialog = new AddDialog(...
Does this compile? Really?
The 'new' operator returns a pointer to void, so the code you have posted looks very odd indeed.
The usual way of doing this is:
AddDialog * newAddDialog = (AddDialog *) new AddDialog( ...
Or
AddDialog newAddDialog( ...
After switching from VS2005 to VS2008 SP1, I found an issue that I can't explain.
A program works fine under VS2005 in both release and debug mode. Under VS2008, when entering the debugger an assert is raised.
If I let the program run (in debug or release mode), no assertion at all.
I spent almost two days on this and I don't understand what I do wrong.
Description of the program:
I have a MFC dialog based program that creates a user thread (CWinThread) that creates the main dialog of the application.
A worker thread loops infinitely and posts each second a message to the dialog. The message is processed in the gui thread.
Some parts of my code:
The InitInstance of the gui thread:
BOOL CGraphicalThread::InitInstance()
{
CGUIThreadDlg* pDlg = new CGUIThreadDlg();
pDlg->Create(CGUIThreadDlg::IDD);
m_pMainWnd = pDlg;
AfxGetApp()->m_pMainWnd = pDlg;
return TRUE;
}
The worker thread:
UINT ThreadProc(LPVOID pVoid)
{
do
{
AfxGetApp()->m_pMainWnd->PostMessage(WM_APP+1, (WPARAM)new CString("Hello"), NULL);
Sleep(1000);
}
while(!bStopThread);
return 0;
}
The dialog message handler is like this:
LRESULT CGUIThreadDlg::OnMsg(WPARAM wp, LPARAM lp)
{
CListBox* pList = (CListBox*)GetDlgItem(IDC_LIST1);
CString* ps = (CString*)wp;
pList->InsertString(-1, *ps);
delete ps;
return 1L;
}
This works perfectly fine with VS2005.
But with VS2008, but as soon as a put a breakpoint and enter the debugging mode, I have an assertion raised ???
wincore.cpp line 906
CObject* p=NULL;
if(pMap)
{
ASSERT( (p = pMap->LookupPermanent(m_hWnd)) != NULL ||
(p = pMap->LookupTemporary(m_hWnd)) != NULL);
}
ASSERT((CWnd*)p == this); // must be us
// Note: if either of the above asserts fire and you are
// writing a multithreaded application, it is likely that
// you have passed a C++ object from one thread to another
// and have used that object in a way that was not intended.
// (only simple inline wrapper functions should be used)
//
// In general, CWnd objects should be passed by HWND from
// one thread to another. The receiving thread can wrap
// the HWND with a CWnd object by using CWnd::FromHandle.
//
// It is dangerous to pass C++ objects from one thread to
// another, unless the objects are designed to be used in
// such a manner.
If I remove the GUI thread and create the dialog into the CWinApp thread, the problem doesn't occur anymore.
Does anybody have any idea?
Am I doing something wrong?
Thank you
// Note: if either of the above asserts fire and you are
// writing a multithreaded application, it is likely that
// you have passed a C++ object from one thread to another
// and have used that object in a way that was not intended.
// (only simple inline wrapper functions should be used)
//
// In general, CWnd objects should be passed by HWND from
// one thread to another. The receiving thread can wrap
// the HWND with a CWnd object by using CWnd::FromHandle.
//
// It is dangerous to pass C++ objects from one thread to
// another, unless the objects are designed to be used in
// such a manner.
#Ismael: I had already tried that the assert is still fired. The only way I found to remove the assert is to create the dialog into the CWinApp thread.
But this doesn't explain what happens since there's still the worker thread that post to the dialog every second.
Anyway , thanks.
#daanish.rumani: I've checked the wincore.cpp and the CWnd::AssertValid() is exactly the same (but there's of lot of differences in the rest of the files).
I would accept that a piece of code works with VS2005 and not VS2008, but
I can't see what I do wrong.
If I do something wrong, what is the correct way to proceed?
Why the assert is only fired when a breakpoint is hit and I step over the Sleep call?
I can run the program fine, even when its compiled in debug mode, as long as I don't enter the debugger.
Could it be a bug in the debugger?