|
|
Comments and Discussions
|
|
 |

|
Thanks for writing this article. In the past I have already created modeless dialogs. But reading your article is much more funny than looking into my old code
|
|
|
|

|
Wrote this 12 years ago, and am sure glad to hear that people still find it useful
|
|
|
|

|
I'm maintaining a largish MFC/COM app where there are approx 50 COM/ATL classes/dlls which call dialogues as children of the main app window. I've added a button to one of the dialogues that effectively puts up a grandchild of a dialogue called by the main frame. Initially it works fine but clicking the mouse in the main frame outside the parent causes an exception which crashes the app. Is there a well-known issue connected to modeless dialogues, message pumps & critical section memory exceptions that I should be handling? I'm not at work right now but if anyone needs clarification I'll VPN in to work & get more info.
|
|
|
|

|
If you close the main dialog with the modeless dialog still showing, you need to delete it:
void CModelessDemoDlg::OnDestroy()
{
if (NULL != m_pmodeless)
{
m_pmodeless->m_pParent = NULL;
m_pmodeless->DestroyWindow ();
m_pmodeless = NULL;
}
CDialog::OnDestroy();
}
|
|
|
|

|
contains all the necessary details
|
|
|
|

|
Thanks, glad to hear that!
|
|
|
|
|

|
Indivara wrote: (never imagined this would still be come in handy. CP rocks!)
Thank you. 9 year old article getting a comment - that was unexpected
|
|
|
|

|
This summary has save a lot of time for me.
|
|
|
|
|

|
this is very helpful.
How do I pass data to the modeless dialog?
|
|
|
|

|
Hi Nish,
I recognise you because I've seen many interesting articles by you, but I never directly used them before. Today, I needed to launch a modeless dialog from an MFC DLL and I Googled around for how to do it. Your article was the most helpful in getting the job done, showing code examples and also how to use the Desktop as the parent window. By the way, I ended up having to use CWnd::FromHandle to convert the desktop's HWND to a CWnd*. The regulars on CodeProject seem to be the most useful educational resources on the internet. Thanks for taking the time to put up stuff like this.
I had been hesitant to use resource files, because there's a learning curve relative to just having headers and source code, but I realized it's super easy to just use the Form designer to design my dialog as a class. MFC programming is a bit weird like that, it seems very complicated with all the stuff happening behind the scenes, but once you know what you're doing it gets really easy.
|
|
|
|

|
Thanks for your article, I was able to create and call a modeless window.. but i have a problem..
first problem is that, my modeless window does not become active.. when i press an ok button, the modeless window is displayed at the background... if there are other open windows present in the desktop, then i cannot see the modeless window.. then when i press the modeless window, the title bar is still light colored.. meaning, its not active.. but the thing is that, I can press the button and do the functions in that modeless windo even if it is not active.......
my question is, whats wrong with my program?? this is a code from which i read in your article..
CVideoControlDlg* VCDlg = new CVideoControlDlg(this);
VCDlg->Create( CVideoControlDlg::IDD, GetDesktopWindow());
VCDlg->ShowWindow(SW_SHOW);
in addition, how can i call the main window back from the child window?? for example, i pushed a close button in the modeless window, how can i call the parent window???
please do reply... thanks..
|
|
|
|

|
Hi,
I have many libaries and about 600 executables written in C++. For the work I am doing, I am only looking at changing one of the libaries. The code is written using Visual C++ on a windows PC. But productionized on IBM mainframe. But, for the purpose of developer testing and debugging, we have got few classes subclassed from the main classes in that library and these Windows specific classes will be used if a particular compiler setting is used.
As this libary (written long time back by someone else) currently stands, each program will add fields to a modal dialog resource at run time. When the dialog shows, user will enter some details in the edit fields and press "Enter". When running on Windows, on the user pressing "Enter" key, just before the dialog class calls the CDialog::EndDialog, it captures the screen shot of this dialog and brings up a pop-up window and called the CDialog::EndDialog. The libary then does work with the user's input, validates that input and depending on which program, does different things. But, if the validation fails, then it will bring up the original modal dialog with a message saying what was invalid along the last field. If the validation has been successful, it will create a new process for another program and once that new program's window comes up, the first program will exit.
Need for change - Displaying the screen shot is not useful, as users want menu items on the dialogs. I can't give menu items on a screen shot. So, I decided to create a modeless dialog (using the same dialog resource as the modal dialog) instead of using the screen shot. This modeless dialog will be populated with the same fields as the originial modal dialog has. Now, when creating the modeless dialog, if I pass the modal dialog class object as the parent of the modeless dialog, then when the modal dialog is ended, the modeless dialog is also deleted. Therefore, when creating the modeless dialog object, I am passing the DesktopWindow as the parent.
When I run the program, I get the modeless dialog shown without showing the fields. So, I commented out the code that will destroy the modeless dialog when the modal dialog appears again. When I run the application, modal dialog appears, user enters details and presses "Enter", modeless dialog appears without fields being shown, modal dialog disappears, validation takes place, the modal dialog appears again and NOW, the fields are populated in the modeless dialog.
Debugging to find out why the fields were not showing did not give me any information. So, I changed the modeless dialog. This time, I created a new dialog resource with a static text field saying "Processing". Instead of the previous modeless dialog, now the modal dialog class object will create the new modeless dialog. Again, the static text was not displayed until the modal dialog appeared for the second time.
Any clue on why the modeless dialog does not show the static text (and my original modeless dialog does not show the fields) when it is shown?
Thank you.
Rgds,
pvasanthi
|
|
|
|

|
Hi. I had the same problem as you with only 1 line of static text in the dialog box. Found the solution after some googling. The modeless dialogbox starts a new thread, and the update of it might be stopped if it doesn't get enough processor time. Add a call to UpdateWindow() just after ShowWindow() and the fields will be shown.. At least my text was. My code became something like this. CDialog dlg; dlg.Create(IDD_INITIALIZING, this); dlg.ShowWindow(SH_SHOW); dlg.UpdateWindow(); //....Do some other code...... dlg.DestroyWindow();
Regards Roar.
|
|
|
|

|
hi,
i have a dialog box called parent with a button in the dialog..on click of the button i need to open a modeless dialog..
the modeless dialog has a edit box in it..on click of that button which is there in parent, a message "hello" needs to be displayed in the edit box of modeless dialog..i dont know how to exactly write into edit box of the modeless dialog..
can someone pls help as soon as possible as i need to use it in my project..
thanks in advance..
|
|
|
|

|
As far i am conserned it must be storing in heap, is their any possiblity to store a modeless dialog in stack memory
Prabodh
|
|
|
|

|
You can make it a member variable of a class whose instance will be alive long enough for you to use the modeless dialog.
|
|
|
|

|
I read the article above, it's nice, but it's definately not the the easiest method of achieving a modeless dialog box.
In your method you have to override a virtual function, post a message from the dialog to the parent, and then respond to a posted message inside of the parent. Too many steps to be called easy.
Here is a simplier approach:
STEP 1: ParentClass.h --> add member variable to modeless dialog
STEP 2: ParentClass.cpp::OnInitDialog()
{
...
m_myModeless.Create(CModelessclass.IDD,NULL);
}
STEP 3: SomeOnButtonShowDialog()
{ // this will ALWAYS work!
m_myModeless.ShowWindow(SW_NORMAL);
}
Additional Suggestions for the modeless dialog:
Don't actually close the dialogbox when you click "OK", just hide the window! When the parent needs to show it again, invariably it will call the same function to show the dialogbox - in otherwords, the parent will use SomeOnButtonShowDialog()
When the application ends, the parent can just call a function in the modeless dialogbox to call the dialog's real OnOK();
So maybe add a STEP 4: Modeless Dialog::OnRealOK()
{
CDialog::OnOK();
}
Maybe it sounds like the same number of steps; but the implementation is a no-brainer. No memory allocation problems, no odd virtual functions to worry about; and no need to recreate the same dialogbox over and over again!
|
|
|
|

|
True,
I this method due that it is much simple
The only problem is when you want to use a modeless dialog based on a
sub-class of CDialog, (E.g. CResizableDialog[^]) then you get a compiler complain:
Warning: calling DestroyWindow in CWnd::~CWnd; OnDestroy or PostNcDestroy in derived class will not be called.
Warning: calling DestroyWindow in CDialog::~CDialog --
OnDestroy or PostNcDestroy in derived class will not be called.
The problem above occurs only if you want the Modeless Dialog parent to be the DesktopWindow instead of your application window:
. . .
m_regsDlg.Create(IDD_REGISTERS_DIALOG, GetDesktopWindow());
. . .
Do you know how to overcome to this complain?
Thanks.
-- Ricky Marek (AKA: rbid)
-- "Things are only impossible until they are not" --- Jean-Luc Picard
My articles
modified on Sunday, September 14, 2008 9:11 AM
|
|
|
|

|
I'm trying to place that dialog on the MainFrame of a MDI app.
The problem is that if i set the parrent of the CDialog to the MainFrame or NULL it will stay on top of all other Doc/View/Frame items
I tried to use GetDesktopWindow but the app crashes with "Acces violation".
Any poiters? How do i fix this? Is this aproach wrong all together?
|
|
|
|

|
Hi,
i wanted to change the dialog's parent by calling setparent.but there is paint problem...i tried setowner also...i don't want to destroy for changing parent...please help me.
|
|
|
|

|
I tried compiling the example code and got the following errors
I am using Visual Studio - VC C++ with the latest service packs installed
I am a newbie so any help would be appreciated
Thank you
-----------------------------------------------------
-------------------Configuration: ModelessDemoDlg - Win32 Debug--------------------
Compiling...
ModelessDemoDlg.cpp
Linking...
ModelessDemoDlg.obj : error LNK2001: unresolved external symbol "public: __thiscall CModeless::CModeless(class CWnd *)" (??0CModeless@@QAE@PAVCWnd@@@Z)
nafxcwd.lib(thrdcore.obj) : error LNK2001: unresolved external symbol __endthreadex
nafxcwd.lib(thrdcore.obj) : error LNK2001: unresolved external symbol __beginthreadex
libcd.lib(crt0.obj) : error LNK2001: unresolved external symbol _main
Debug/ModelessDemoDlg.exe : fatal error LNK1120: 4 unresolved externals
Error executing link.exe.
ModelessDemoDlg.exe - 5 error(s), 0 warning(s)
|
|
|
|

|
I have two modeless dialog, CDialog1, CDialog2, I use the two dialog in a formview. The formview have a member variable CDialog *m_pDlg;
In CDialog1 and CDialog2 I haven't rewrite PostNcDestroy() to delete themselves.
I use them like this:
CMyForm::CMyForm() : m_pDlg(NULL)
{
}
void CMyForm::OnDestroy()
{
DestroyDlg();
}
void CMyForm::DestroyDlg()
{
if (m_pDlg)
{
m_pDlg->DestroyWindow();
delete m_pDlg;
m_pDlg = NULL;
}
}
short nDlgFlag = -1;
void CMyForm::OnBtn1()
{
if (nDlgFlag == 0)
return;
nDlgFlag = 0;
DestroyDlg();
m_pDlg = new CDialog1;
m_pDlg->Create(IDD_DIALOG1, this);
m_pDlg->ShowWindow(SW_SHOW);
}
void CMyForm::OnBtn2()
{
if (nDlgFlag == 1)
return;
nDlgFlag = 1;
DestroyDlg();
m_pDlg = new CDialog2;
m_pDlg->Create(IDD_DIALOG2, this);
m_pDlg->ShowWindow(SW_SHOW);
}
My question is when i click button1 and then button2 the taskmanager show that the appliction used memory increased, but when i minimize it the used memory decreased to lower, and show again the memory used lower than before minimized, I don't know why. Any one help me.
Is there any function can do this but needn't to mimimize it.
Thanks a lot.
Hongjun Ge
|
|
|
|

|
I receive a memory block of an image from the main dialog, and want to put that image to the modeless. Any one know how to do it ? Thanks....
|
|
|
|

|
I have a modal dialog which creates a modeless dialog to run a progress bar. The problem is that the modal parent becomes non modal as soon as the modeless dialog is created. ie I can now switch to the main application and close it for example while the original modal dialog is still running.
Has anyone come across this problem and is there a way around it?
Jeff
|
|
|
|

|
In EVC 4.0, I created a modeless dialog according to your way and compiled it successfully, however, the EVC compiling tool reported an error after I added to "pdlg->Create(CInstallingDlg::IDD;,GetDesktopWindow());"
The error is:
error C2664: 'int __cdecl CDialog::Create(const unsigned short *,class CWnd *)' : cannot convert parameter 1 from 'enum ' to 'const unsigned short *'
How to correct it?
Thanks in advance!
|
|
|
|

|
Any idea to update CEdit in dlg class form non MFC Class
NonMFCClass::abc()
{
//got a public member CEdit *ed
ed->SetWindowText("fdf");
}
CDlgc::onButton1()
{
//m_ed is member var dlg class
ed=&m_ed;
}
text not getting updated
I want to update cedit form non mfc class only
kattavictor
|
|
|
|

|
Hi,
I have an MFC control wich pops up a dialog box, it used to work as modal dialog, but when i switched to modeless dialog box, it no more go through the prestranslateMessage of the dialog nor of the CEdit of the dialog, where i do some treatment, any hint pls ?
Thanks
|
|
|
|

|
I am having the same problem. Any help is appreciated.
|
|
|
|

|
Yeah I too am facing the same issue. My modeless CDialog window
wont process the PreTranslateMessage().. What could be the problem?
Do non-modal CDialog windows process it at all?
Expecting some tips. Or links references maybe. Plz.
pc assembling: http://pcassembler.tripod.com
|
|
|
|
|

|
A guess if I understand your concern:
Even if modeless there is still a single Messages loop. The one initiated with creation of top parent (it is even said that message loop is only initiated on first message).
This is probably where pretranslate is handled.
If you want your own Messages loop either build it (be carefull to de-interleave message of/for Parent).
Or, safer, use the purposedly defined GUIThread which in turn will start your Dialog (which de facto become modeless kind)
but GuiThread is heavylift to deploy.
Gordon
|
|
|
|

|
I have created a modeless dialog which is instantiated and parented from a CFormView object in an MDI application. When I look at the parent in the constructor (using the debugger) it shows that the parent is the CFormView (as I would expect).
As part of the control handlers for my dialog I want to send a message to the parent view, so I tried to use GetParent to retrieve the view - instead of the view, GetParent returns the CMainFrame of my application...
To work around the problem, I have stored the view in a member variable during the dialog construction and use this when I want to send my message.
Any ideas why GetParent is returning CMainFrame rather than my CFormView?
Thanks in advance for nay help
Regards,
Rich
|
|
|
|

|
hope this helps...
i usually use GetActiveView instead of storing the view pointer. then use SendMessage to the view(parent).
|
|
|
|

|
Hi, Happy to see ur Article on Modeless Dialog , I have one Progress Bar Control and a Static Text and a Cancel Button .
When I create a Modeless Dialog before my another long process statrs, only Dialog will appear on the desk top , but not any controls of the dialog..
I want show the progress bar / animation on the mode less dialog . please help me
|
|
|
|

|
In my case, GetParent() cause fails becase m_hWnd is alread NULL when it comes to PostNcDestroy.
( I'm using Visual C++ 6.0.)
So I chaned my code to use memeber variable whichs stores the parent window.
|
|
|
|

|
I have a question regarding the use of pointers for modeless dialogs.
I want to use a non-pointer member variable in my CFrameWnd derived class (CMyDialog m_dialog). Then in my
OnCreate function (CFrameWnd derived class):
m_dialog.Create(IDD_DIALOG,this);
m_dialog.ShowWindow(SW_SHOW);
Then in my OnDestroy function:
m_dialog.DestroyWindow();
I would like to know if there are any problems with this approach (memory leaks, bugs, etc.).
|
|
|
|

|
If anyone of you have any idea about passing data back to parent window, please, do let me know (and sorry I am just a beginner). Any advice how to make it easier or whatever ... THANK YOU ...
Usage of direct type cast has a disandvantage. Child is forced to have parent window of one class (CMainFrame).
((CMainFrame*)GetParent())-> ...
I use (no type cast is needed):
GetParent()->SendMessage( ON_COMMAND, ID_MY_MSG_FROM_CHILD );
And a parent knows the type of child windows, so type casting is Ok. I use lParam to get pointer to child, because parent could have more than one child of the same type (CChildWnd). A these ones use the same message ID_MY_MSG_FROM_CHILD to let the parent know.
BOOL CMyParentWnd::OnCommand(WPARAM wParam, LPARAM lParam)
{
if( wParam == ID_MY_MSG_FROM_CHILD )
{
CChildWnd* pw =
(CChildWnd*) FromHandlePermanent( (HWND)lParam );
ASSERT(pw);
pw->GetData(...);
return TRUE;
}
return CWnd::OnCommand(wParam, lParam);
}
|
|
|
|

|
The MFC framework does not automatically center it. To center it, call the CenterWindow function inside the dialog box OnInitDialog handler.
(I am just a beginner and did not know how to center a modeless dialog. So, someone like me maybe will find it quicker, when it is mentioned here.)
|
|
|
|

|
Hi,
Just to test the modeless, i added a button to the child and i put a sleep inside that button. When i clicked that button it freezes parent as well. Why? if its true modeless it should not affect the other dialogs, isn't it?
-Ramanan
|
|
|
|

|
You have not understood modeless (sorry if you have understood by now). Modeless only allows you to go to other dialog boxes and windows. It does not mean the appication is running in multiple threads. Only if your application is running in multiple threads, you can see one thread sleeping and other working properly. This modeless dialog will still haev only one process and it will get stuck if you have sleep.
|
|
|
|

|
Thanks for it. Any way i didn't get a clear picture from ur reply. But i got it from another thread which i posted at the same time. Here is that...
http://www.codeproject.com/dialog/modeless_tracker.asp?msg=881977#xx881977xx
All dialog based applications in windows are in one process, But can run threads. What i got 2 kno is all the dialogs evn though its modeless it runs on a single thread.
-Ramanan
|
|
|
|

|
Hi Nishant,
As has already been stated - great article. The ability to create and command a modeless dialog is just one of those skills you must have.
I have implemented your code in an MDI project using the post message option to inform the parent window (main frame) that it should set the pointer to NULL, and it works fine, providing I send the message from OnOk() and OnCancel() and not OnNcDestroy() as was pointed out by Lucy.
However, if when creating the dialog box I use GetDesktopWindow() as you suggest, my program crashes when you close the dialog. Here is the pertinant code:
void CMainFrame::OnViewModelessdialog()
{
if (modeless_dialog)
modeless_dialog->SetForegroundWindow();
else {
modeless_dialog = new CModelessDlg;
modeless_dialog->Create(CModelessDlg::IDD,GetDesktopWindow());
modeless_dialog->ShowWindow(SW_SHOW);
}
}
What other changes are required given the change of parent?
|
|
|
|

|
.. of my modeless dialog.
how do i keep track of them, a list of pointers maybe?
thanks
|
|
|
|

|
Hope it's not too late...
you can create a static int member variable(counter) in the modeless dialog class. on WM_CREATE, increment this counter. everytime you create an instance of this modeless dialog, you can check the static counter about how many times it has been created.
also, on PostNCDestroy, decrement the counter.
|
|
|
|
|

|
Well done, all solutions are in this page.
Thanx that did save me a lot of time.
|
|
|
|

|
Very nice. I read about modeless dialog boxes in Prosise and wasn't able to follow everything clearly. This article helped me build one on my own.
Thank you
" Why oh why didn't I take the blue pill ? "
|
|
|
|

|
I have a MS Visual Studio.Net application written in C++. What I want to do is to monitor memory as the program allocates and deallocates memory.
I want to make sure memory is deallocated at the proper time, etc. How can I do this??
Jerry
|
|
|
|
 |
|
|
General News Suggestion Question Bug Answer Joke Rant Admin
Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.
|
Some tips/suggestions on using modeless dialogs with MFC
| Type | Article |
| Licence | CPOL |
| First Posted | 6 Dec 2001 |
| Views | 512,064 |
| Bookmarked | 136 times |
|
|