Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

AfxGetMainWnd () call

47 views
Skip to first unread message

mfc

unread,
Oct 15, 2010, 3:37:30 PM10/15/10
to
Hi,

I`ve a CFormView in my SDI application as well as a dialog where the
user can change some settings to specific parts of the software. After
clicking on the "ok"-button I will create another dialog (CWaitDialog)
to verify all these settings the user has made.

I`m not sure if it is recommended to use the constructor to start this
dialog as well as the use of AfxGetMainWnd() (of course in the
mainthread). I`m not really sure in which situations it makes sense to
call such a global method.


CWaitDialog::CWaitDialog (BOOL pFlag, CString& pszCaption, CString&
pszText) : CDialog ()
{
m_pFlag = pFlag;

// Disable the main window and create the dialog.
AfxGetMainWnd ()->EnableWindow (FALSE);
Create (IDD_WAITDIALOG);

// Initialize the dialog caption and the static text control.
SetWindowText ((pszCaption.GetLength()) ? _T("Working") :
pszCaption);

// Display the dialog.
ShowWindow (SW_SHOW);
}


and here is my call of this dialog in the method OnWizardFinish()
which will be called if the user clicks the "ok" button to update his
settings.

void CWizardDialog::OnWizardFinish()
{
BOOL bContinue = TRUE;
BOOL stillWorking = TRUE;

CString dialogtitle ("Please wait...");
CString dialogtext ("Wait for me to do my stuff...");
CWaitDialog dlg (bContinue, dialogtitle, dialogtext);

while (stillWorking && bContinue)
{
//verify all data

//add message to dialog if verifcation failed (to inform the
user)
}

//finished
dlg.Close();
}


best regards
Hans

ScottMcP [MVP]

unread,
Oct 15, 2010, 8:00:27 PM10/15/10
to

If the while loop is brief then you are flashing up a dialog and then
removing it, which will be annoying to the user. If the while loop is
lengthy it blocks painting and responding to input, which will be
annoying to the user. So the whole concept is kind of clumsy.

Calling Create in the dialog constructor is the normal way to create a
modeless dialog. But disabling the mainframe has the effect of making
the dialog modal. So you have created a modal modeless dialog? And
it disappears all by itself? I think you need to take a few steps
back and consider how best to present whatever you are trying to
present to the user.

Joseph M. Newcomer

unread,
Oct 15, 2010, 11:45:42 PM10/15/10
to
See below...

On Fri, 15 Oct 2010 12:37:30 -0700 (PDT), mfc <mfc...@googlemail.com> wrote:

>Hi,
>
>I`ve a CFormView in my SDI application as well as a dialog where the
>user can change some settings to specific parts of the software. After
>clicking on the "ok"-button I will create another dialog (CWaitDialog)
>to verify all these settings the user has made.
>
>I`m not sure if it is recommended to use the constructor to start this
>dialog as well as the use of AfxGetMainWnd() (of course in the
>mainthread). I`m not really sure in which situations it makes sense to
>call such a global method.
>
>
>CWaitDialog::CWaitDialog (BOOL pFlag, CString& pszCaption, CString&

****
I'm curious why it isn't const CString & for the values; and why 'psz' since it is not a
pointer...
****


>pszText) : CDialog ()
>{
> m_pFlag = pFlag;
>
> // Disable the main window and create the dialog.
> AfxGetMainWnd ()->EnableWindow (FALSE);
> Create (IDD_WAITDIALOG);

****
This would be
Create(CWaitDialog::IDD);
and I note that you do not check the return value to see if it worked...
****


>
> // Initialize the dialog caption and the static text control.
> SetWindowText ((pszCaption.GetLength()) ? _T("Working") :
>pszCaption);

****
That would be
SetWindowText(pszCaption.IsEmpty() ? _T("Working") : pszCaption);
****

>
> // Display the dialog.
> ShowWindow (SW_SHOW);
>}
>
>
>and here is my call of this dialog in the method OnWizardFinish()
>which will be called if the user clicks the "ok" button to update his
>settings.
>
>void CWizardDialog::OnWizardFinish()
>{
> BOOL bContinue = TRUE;
> BOOL stillWorking = TRUE;
>
> CString dialogtitle ("Please wait...");
> CString dialogtext ("Wait for me to do my stuff...");

****
Note that you should not include English words in literal strings in a program; it makes
localization very difficult.
****


> CWaitDialog dlg (bContinue, dialogtitle, dialogtext);
>
> while (stillWorking && bContinue)
> {
> //verify all data
>
> //add message to dialog if verifcation failed (to inform the
>user)
> }

****
There is something odd here; for example, why is the dialog allowed to be closed if the
data isn't valid? You should be verifying the data before you allow the dialog to close!

I'd throw all this code out and start over. Do a modal dialog, don't let it close until
the data is verified (don't even enable the OK button!)
joe
****


>
> //finished
> dlg.Close();
>}
>
>
>best regards
>Hans

Joseph M. Newcomer [MVP]
email: newc...@flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm

mfc

unread,
Oct 16, 2010, 4:05:58 PM10/16/10
to

I agree; but some data to verfiy will take some time - for example
verifying the network settings (ip-ping or searching for a dhcp
server); and both the dialog as well as verfiying the data will be in
the same thread.

Therefore maybe it`s ok to open the waitdialog for the user to verfiy
all his settings; but if these settings are not ok, then I will only
close the waitdialog so that the user can made some changes to fix
these errors.

best regards
Hans


>
> I'd throw all this code out and start over.  Do a modal dialog, don't let it close until
> the data is verified (don't even enable the OK button!)
>                         joe
> ****


>
> >   //finished
> >   dlg.Close();
> >}
>
> >best regards
> >Hans
>
> Joseph M. Newcomer [MVP]

> email: newco...@flounder.com
> Web:http://www.flounder.com
> MVP Tips:http://www.flounder.com/mvp_tips.htm- Zitierten Text ausblenden -
>
> - Zitierten Text anzeigen -

Joseph M. Newcomer

unread,
Oct 16, 2010, 10:42:35 PM10/16/10
to
See below...

***
In that case, clicking OK could launch another modal dialog that indicated checking was in
progress. If that dialog completes OK, then your dialog continues by calling
CDIalog::OnOK; if it fails to verify, it returns some other code, and you just return
immediately without calling CDialog::OnOK. You have taken a very simple problem and made
it incredibly difficult by this notion of having dialogs that are modeless and work as
your code illustrates.
joe
****


>these errors.
>
>best regards
>Hans
>>
>> I'd throw all this code out and start over. �Do a modal dialog, don't let it close until
>> the data is verified (don't even enable the OK button!)
>> � � � � � � � � � � � � joe
>> ****
>
>
>
>
>>
>> > � //finished
>> > � dlg.Close();
>> >}
>>
>> >best regards
>> >Hans
>>
>> Joseph M. Newcomer [MVP]
>> email: newco...@flounder.com
>> Web:http://www.flounder.com
>> MVP Tips:http://www.flounder.com/mvp_tips.htm- Zitierten Text ausblenden -
>>
>> - Zitierten Text anzeigen -
Joseph M. Newcomer [MVP]

email: newc...@flounder.com

mfc

unread,
Oct 17, 2010, 6:36:32 AM10/17/10
to
> ***
> In that case, clicking OK could launch another modal dialog that indicated checking was in
> progress.  If that dialog completes OK, then your dialog continues by calling
> CDIalog::OnOK; if it fails to verify, it returns some other code, and you just return
> immediately without calling CDialog::OnOK.  You have taken a very simple problem and made
> it incredibly difficult by this notion of having dialogs that are modeless and work as
> your code illustrates.
>                         joe
> ****
>

And how should that work with a modal dialog? If I call dlg.DoModal()
I can do nothing - no verifycation. But I want to show this
CWaitingDialog() and at the same time I want to verify all the
settings the user made.

void CWizardDialog::OnWizardFinish()
{
CWaitDialog dlg;
BOOL rtn = dlg.DoModal();

}


INT_PTR CWaitDialog ::DoModal()
{
CDialog:.DoModal();

BOOL rtn = pWizDlg->VerfiyData();

return rtn;
}

best regards
Hans

Joseph M. Newcomer

unread,
Oct 17, 2010, 2:39:35 PM10/17/10
to
See below...

On Sun, 17 Oct 2010 03:36:32 -0700 (PDT), mfc <mfc...@googlemail.com> wrote:

>> ***
>> In that case, clicking OK could launch another modal dialog that indicated checking was in
>> progress. �If that dialog completes OK, then your dialog continues by calling
>> CDIalog::OnOK; if it fails to verify, it returns some other code, and you just return
>> immediately without calling CDialog::OnOK. �You have taken a very simple problem and made
>> it incredibly difficult by this notion of having dialogs that are modeless and work as
>> your code illustrates.
>> � � � � � � � � � � � � joe
>> ****
>>
>
>And how should that work with a modal dialog? If I call dlg.DoModal()
>I can do nothing - no verifycation. But I want to show this
>CWaitingDialog() and at the same time I want to verify all the
>settings the user made.

****
There is no reason to assume you cannot do any verification! In fact, the statement makes
no sense!

What is the problem with doing verification? You call some subroutine to do verification,
and it returns either true or false. If it is true, you proceed with what you were going
to do; if it was false, you do not.
****


>
>void CWizardDialog::OnWizardFinish()
>{
> CWaitDialog dlg;
> BOOL rtn = dlg.DoModal();

*****
I am curious why you declared OnWizardFinish to be void; RTFM. According to the
documentation the declaration is
virtual BOOL OnWizardFinish();
and it says explicitly to return FALSE to prevent the property page from being destroyed.

So if the validation fails, you return FALSE.

I note also that you have done
BOOL rtn = dlg.DoModal();
which is going to return, most commonly, OnOK or OnCancel. So why do you assume it is a
BOOL? When the validation finishes, you would call CDialog::OnOK(); if it fails, you
would call CDialog:::OnCancel(). You would have to override the built-in OnOK and
OnCancel handlers, as well as OnClose, to all do nothing, so the user cannot kill the
modal diaog while the validation is occurring (unless, of course, you WANT this to be
possible! In which case, OnClose would call CDialog::OnCancel()).

joe
****


>
>}
>
>
>INT_PTR CWaitDialog ::DoModal()
>{
> CDialog:.DoModal();
>
> BOOL rtn = pWizDlg->VerfiyData();
>
> return rtn;
>}
>
>best regards
>Hans

mfc

unread,
Oct 17, 2010, 2:48:04 PM10/17/10
to
On 17 Okt., 20:39, Joseph M. Newcomer <newco...@flounder.com> wrote:
> See below...
>
>
>
>
>
> On Sun, 17 Oct 2010 03:36:32 -0700 (PDT), mfc <mfcp...@googlemail.com> wrote:
> >> ***
> >> In that case, clicking OK could launch another modal dialog that indicated checking was in
> >> progress.  If that dialog completes OK, then your dialog continues by calling
> >> CDIalog::OnOK; if it fails to verify, it returns some other code, and you just return
> >> immediately without calling CDialog::OnOK.  You have taken a very simple problem and made
> >> it incredibly difficult by this notion of having dialogs that are modeless and work as
> >> your code illustrates.
> >>                         joe
> >> ****
>
> >And how should that work with a modal dialog? If I call dlg.DoModal()
> >I can do nothing - no verifycation. But I want to show this
> >CWaitingDialog() and at the same time I want to verify all the
> >settings the user made.
>
> ****
> There is no reason to assume you cannot do any verification!  In fact, the statement makes
> no sense!
>
> What is the problem with doing verification?  You call some subroutine to do verification,
> and it returns either true or false.  If it is true, you proceed with what you were going
> to do; if it was false, you do not.
> ****

Sorry I didn`t understand what you exactly mean. If I call the
dlg.DoModal() method I can`t call any subroutine to do all the
verifycations.

- first step: show waiting dialog
- second step: do all required verfiycations
- depending on the result of the verifycations go back to the mainmenu
or stay in the wizard-dialog.

After calling

CWaitDialog dlg;
dlg.DoModal();

how can you call the subroutine to do the verifycations? Can you show
me a small example?

> >void CWizardDialog::OnWizardFinish()
> >{
> >   CWaitDialog dlg;
> >   BOOL rtn = dlg.DoModal();
>
> *****
> I am curious why you declared OnWizardFinish to be void; RTFM.  According to the
> documentation the declaration is
>         virtual BOOL OnWizardFinish();
> and it says explicitly to return FALSE to prevent the property page from being destroyed.

Thats true I wrote this code on scratch.

best regards
Hans

Message has been deleted

Goran

unread,
Oct 18, 2010, 3:19:35 AM10/18/10
to
On Oct 17, 12:36 pm, mfc <mfcp...@googlemail.com> wrote:
> And how should that work with a modal dialog? If I call dlg.DoModal()
> I can do nothing - no verifycation. But I want to show this
> CWaitingDialog() and at the same time I want to verify all the
> settings the user made.

By far the best way to do this is to spin another thread and do
verification there. While doing that, put-up a "please wait" modal
dialog. Think about it: you want to do two things at the same time.
Well, use two threads, why dabbling in anything else!?

That said, can you process messages while verifying? Normally no, but
you can spuriously call likes of Tom Serface's GiveTime function in it
(search for it in this very newsgroup). That's an easy, albeit
somewhat ugly solution. What I don't like about it is that it spins
yet another message loop, messes with "normal" WM_QUIT processing, and
it's not easy to know when to call it from the calculation.

Others have said it, but it seems to be worth repeating: your idea
with a modeless dialog is just not good. Note that even if you show
the window, and if you don't process messages, your UI will still be
frozen while verifying. If that is so, Joe's idea of poping up a
"Verifying, please wait" text as a child of a wizard page easily beats
your modeless dialog idea.

Goran.

mfc

unread,
Oct 18, 2010, 2:07:46 PM10/18/10
to
> >> ****
>
> >Sorry I didn`t understand what you exactly mean. If I call the
> >dlg.DoModal() method I can`t call any subroutine to do all the
> >verifycations.
>
> ****
> Why not?  I presume the reason for calling the modal dialog is to do the verification.
> Therefore, the modal dialog would be doing the verification.

That`s true.

> Of course, if you just want to show a progress bar or say "busy verifying" you can do this
> either by using a modeless dialog or just putting a status message in the current dialog.

Because of your and Gorans help I know that a modeless dialog is not a
great idea. Therefore I don`t want to use one. But my display is very
small, so that I do not have the place to add a additional status
message (static field).... I`ll use this method in my webserver.

> ****
> No,  this is where you went wrong.
>
> First step: Show dialog indicating verification in progress
> Second step: Do verification
> Third step: When verification completes, close dialog
> Fourth step: If verification succeeded, proceed to next state, otherwise, remain in
> current state after issuing error message as to what is wrong

Thanks for your example, but at the moment the dialog is still not
shown because the OnInitDialog() method is called before dlg.DoModal()
as well as the PostMessage.

BOOL CWizardDialog::OnWizardFinish()
{
CWaitDialog dlg;
INT_PTR rtn = dlg.DoModal(); //dialog is not shown
during the verification OnStartValidation()

switch(rtn)
{
case IDOK:
CDialog::EndDialog(ID_WIZFINISH);
break;

case IDCANCEL:
default:
return FALSE;
}

return TRUE;
}


BOOL CWaitDialog::OnInitDialog()
{
CDialog::OnInitDialog();
PostMessage(UWM_START_VALIDATION, 0, 0);
return TRUE;
}


LRESULT CWaitDialog::OnStartValidation(WPARAM, LPARAM)
{
//verification of the information
INT_PTR rtn = pDlg->OnStartValidation();

switch(rtn)
{
case IDOK:
CDialog::OnOK(); //close CWaitDialog()
break;

case IDCANCEL:
CDialog::OnCancel();
break;
}

return TRUE;
}


With this implementation I can call the subroutine to verfiy the
settings the user made. But the dialog CWaitDialog is not shown....


best regards
Hans

Joseph M. Newcomer

unread,
Oct 18, 2010, 3:22:40 PM10/18/10
to
See below...

On Mon, 18 Oct 2010 11:07:46 -0700 (PDT), mfc <mfc...@googlemail.com> wrote:

>> >> ****
>>
>> >Sorry I didn`t understand what you exactly mean. If I call the
>> >dlg.DoModal() method I can`t call any subroutine to do all the
>> >verifycations.
>>
>> ****
>> Why not? �I presume the reason for calling the modal dialog is to do the verification.
>> Therefore, the modal dialog would be doing the verification.
>
>That`s true.
>
>> Of course, if you just want to show a progress bar or say "busy verifying" you can do this
>> either by using a modeless dialog or just putting a status message in the current dialog.
>
>Because of your and Gorans help I know that a modeless dialog is not a
>great idea. Therefore I don`t want to use one. But my display is very
>small, so that I do not have the place to add a additional status
>message (static field).... I`ll use this method in my webserver.
****

Modeless dialogs are neither good nor bad, just a tool, whose use might be appropriate or
inappropriate in a given setting. Given what you are trying to accomplish, I think a
modeless dialog just adds complexity, but it isn't all that hard to use one, as long as
you use it appropriately. Your code was far too complex.
****


>
>> ****
>> No, �this is where you went wrong.
>>
>> First step: Show dialog indicating verification in progress
>> Second step: Do verification
>> Third step: When verification completes, close dialog
>> Fourth step: If verification succeeded, proceed to next state, otherwise, remain in
>> current state after issuing error message as to what is wrong
>
>Thanks for your example, but at the moment the dialog is still not
>shown because the OnInitDialog() method is called before dlg.DoModal()
>as well as the PostMessage.

****
Did you see which OnInitDialog I was using? I was putting it in the CWaitDialog! There
are multiple OnInitDialog functions, and it could not be possibly called before the
DoModall because it is the DoModal that invokes it! So it *must* happen *after* the
DoModal, and necessarily before the PostMessage is processed.

Key here is that you must only call the validation from the PostMessage handler
****


>
>BOOL CWizardDialog::OnWizardFinish()
>{
> CWaitDialog dlg;
> INT_PTR rtn = dlg.DoModal(); //dialog is not shown
>during the verification OnStartValidation()
>
> switch(rtn)
> {
> case IDOK:
> CDialog::EndDialog(ID_WIZFINISH);
> break;
>
> case IDCANCEL:
> default:
> return FALSE;
> }
>
> return TRUE;
>}
>
>
>BOOL CWaitDialog::OnInitDialog()
>{
> CDialog::OnInitDialog();
> PostMessage(UWM_START_VALIDATION, 0, 0);
> return TRUE;

****
After the return TRUE the dialog should be shown. Note, however, that if you manage to
block the message pump, you are in trouble; have you considered doing the validation from
a secondary thread?
****


>}
>
>
>LRESULT CWaitDialog::OnStartValidation(WPARAM, LPARAM)
>{
> //verification of the information
> INT_PTR rtn = pDlg->OnStartValidation();
>
> switch(rtn)
> {
> case IDOK:
> CDialog::OnOK(); //close CWaitDialog()
> break;
>
> case IDCANCEL:
> CDialog::OnCancel();
> break;
> }
>
> return TRUE;
>}
>
>
>With this implementation I can call the subroutine to verfiy the
>settings the user made. But the dialog CWaitDialog is not shown....
>

****
Probably because the message pump is blocked.

Note that if you use a secondary thread it must not touch any of the controls of any
dialog.
joe

****

mfc

unread,
Oct 18, 2010, 4:05:29 PM10/18/10
to

Not so far, and that`s the problem. I do the validation in the same
thread which is the main thread.

Maybe I`ve to use another solution, because this would be very
complicated to use another thread for the verification. Because all
the required data (min and max values for some settings...) is
installed in classes running on the mainthread... The only appropriate
solution would be that the wizard is running on a different thread
than the mainthread to acchieve this.

Or I do the verification and if it fails I use a modal dialog showing
the user that there are some values incorrect. All these items have a
red background color which indicate that there`s something wrong....
If the verification was successful, no dialog will be shown and the
user will get back to the main-menue.

Joseph M. Newcomer

unread,
Oct 18, 2010, 6:10:39 PM10/18/10
to
See below...

****
If the validation takes as long as you suggest, this is probably a serious error. You
should seriously consider spinning off a secondary thread. The GUI is dead as long as the
validation is in progress
****


>
>Maybe I`ve to use another solution, because this would be very
>complicated to use another thread for the verification. Because all
>the required data (min and max values for some settings...) is
>installed in classes running on the mainthread... The only appropriate
>solution would be that the wizard is running on a different thread
>than the mainthread to acchieve this.

****
Really? It is so amazingly simple I wouldn't even think twice about doing it

- Package up the parameters involved in the validation
- Create a worker thread that does the validation
-Upon completion of the validation, the validation thread does a PostMessage back to the
main thread; for example, WPARAM or LPARAM can be used to indicate the result
- A handler for the above message deals with reporting this to the user

See my essay on thread shutdown, where I talk about deferring closing a window; the basic
idea is that you ALWAYS fail the closing of the window, spin off the thread, and based on
validation results, either complete the closing of the window or do nothing

It takes about ten minutes to code it up.
****

>
>Or I do the verification and if it fails I use a modal dialog showing
>the user that there are some values incorrect. All these items have a
>red background color which indicate that there`s something wrong....
>If the verification was successful, no dialog will be shown and the
>user will get back to the main-menue.

****
Seems reasonable.
joe
****

mfc

unread,
Nov 1, 2010, 4:09:13 PM11/1/10
to
>I'd throw all this code out and start over. Do a modal dialog, don't let it close until
>the data is verified (don't even enable the OK button!)

If the verification doesn`t take so much time, it would be propably ok
to use the OnKillActive() method of the cporpertypage class to do the
verification for one dialog-page in the wizard. And if the
verification fails the user can`t go to the next page as well as the
field which has a wrong number etc. will be highlighted...

If the verification will take much longer (e.g. check if the ip addr
is availalbe or searching for a dhcp server), its better to use a
worker thread to validate. Maybe it is easier to valiadate such thing
not in this routine. Working with Windows, you are also able to click
the ok button of the network settings, even if the ip is already
available in the network. A few seconds later you will get a
notification which will show you that....

> ****
> Really?  It is so amazingly simple I wouldn't even think twice about doing it
>
> - Package up the parameters involved in the validation

I wrote a small method to get all these parameters from all dialog
pages, when the user pressed the "ok" button.

void WizardPage::Finish()
{

//map which will include all parameters from all
pages
SubStrMap *map = new SubStrMap;


// notify all pages that we are finishing
POSITION Pos = m_PageList.GetHeadPosition();
while (Pos)
{
pPage = (CWizardPage*)m_PageList.GetNext(Pos);
if (pPage->m_bCreated)
{
//get all settings from each page
pPage->GetParams(*map);
}
}

//threadparams
params = new ThreadParams(NULL, AfxGetMainWnd(), NULL,
map);

//start worker thread for verification
AfxBeginThread(WorkerThreadProc,(LPVOID)
threadparams,THREAD_PRIORITY_NORMAL,0,0,NULL);
}

> - Create a worker thread that does the validation


UINT WorkerThreadProc( LPVOID Param )
{
ThreadParams *params;
params = (ThreadParams*) Param;

SubStrMap *map;
map = (SubStrMap*) params->pdata;

//do verification depending on the menue

params->notifyee->PostMessage(UWM_VERIFY_MSG_COMP, map, error-code if
it failed);

return 0;
}

ThreadParams will include the data to be verified as well as a handle
to send PostMessages and a shutdown event.


> -Upon completion of the validation, the validation thread does a PostMessage back to the
> main thread; for example, WPARAM or LPARAM can be used to indicate the result
> - A handler for the above message deals with reporting this to the user
>
> See my essay on thread shutdown, where I talk about deferring closing a window; the basic
> idea is that you ALWAYS fail the closing of the window, spin off the thread, and based on
> validation results, either complete the closing of the window or do nothing

I will have a look about this subject.


After the verification I will send the map with the values back to the
mainthread - and if there were no errors during the verification - the
mainthread / document will set these values for the network settings,
the serial port settings.... in the xmlfile. If everthing was
successfull I will get back to the dialog (wizard).

I`m not sure if it makes sence to add a modal dialog when the user
presses the ok-button; because apart from the verification of the
network settings, all verifications will take only a short time, so
that the user will see a flickering dialog.... or the user has to
click the okbutton on the waiting-dialog,which will show him that all
changes were made or not...

best regards
Hans

mfc

unread,
Nov 1, 2010, 4:39:16 PM11/1/10
to
in the mainthread I`ll send a PostMessage back to the dialog class. It
works, but I`m not sure if it is the correct way to do that

::PostMessage(GetActiveWindow()->m_hWnd, UWM_VERIFY_END, 0, 0);

best regards
Hans

Joseph M. Newcomer

unread,
Nov 14, 2010, 7:09:15 PM11/14/10
to
See below...

On Mon, 1 Nov 2010 13:09:13 -0700 (PDT), mfc <mfc...@googlemail.com> wrote:

>>I'd throw all this code out and start over. Do a modal dialog, don't let it close until
>>the data is verified (don't even enable the OK button!)
>
>If the verification doesn`t take so much time, it would be propably ok
>to use the OnKillActive() method of the cporpertypage class to do the
>verification for one dialog-page in the wizard. And if the
>verification fails the user can`t go to the next page as well as the
>field which has a wrong number etc. will be highlighted...
>
>If the verification will take much longer (e.g. check if the ip addr
>is availalbe or searching for a dhcp server), its better to use a
>worker thread to validate. Maybe it is easier to valiadate such thing
>not in this routine. Working with Windows, you are also able to click
>the ok button of the network settings, even if the ip is already
>available in the network. A few seconds later you will get a
>notification which will show you that....
****

Well, the checking of an IP address requires a DNS (not DHCP) server, and yes, this would
be a great place to use a thread. But you couldn't block switching, and I really don't
believe that you should EVER block switching pages.

>
>
>
>> ****
>> Really?  It is so amazingly simple I wouldn't even think twice about doing it
>>
>> - Package up the parameters involved in the validation
>
>I wrote a small method to get all these parameters from all dialog
>pages, when the user pressed the "ok" button.
>
>void WizardPage::Finish()
>{
>
> //map which will include all parameters from all
>pages
> SubStrMap *map = new SubStrMap;
>
>
> // notify all pages that we are finishing
> POSITION Pos = m_PageList.GetHeadPosition();
> while (Pos)
> {
> pPage = (CWizardPage*)m_PageList.GetNext(Pos);
> if (pPage->m_bCreated)
> {
> //get all settings from each page
> pPage->GetParams(*map);
> }
> }

****
Not a bad idea, and one I have used in the past. But I've found it clumsy, so these days,
I treat property page sequences (or wizard-page sequences) using a document/view-like
architecture where each page stores its data in its OnKillActive and the "document" object
(which is your SubStrMap) is always filled in. Saves the problem of trying to iterate
over the pages.
joe
****


>
> //threadparams
> params = new ThreadParams(NULL, AfxGetMainWnd(), NULL,
>map);
>
> //start worker thread for verification
> AfxBeginThread(WorkerThreadProc,(LPVOID)
>threadparams,THREAD_PRIORITY_NORMAL,0,0,NULL);
>}
>
>> - Create a worker thread that does the validation
>
>
>UINT WorkerThreadProc( LPVOID Param )
>{
> ThreadParams *params;
> params = (ThreadParams*) Param;
>
> SubStrMap *map;
> map = (SubStrMap*) params->pdata;
>
> //do verification depending on the menue
>
> params->notifyee->PostMessage(UWM_VERIFY_MSG_COMP, map, error-code if
>it failed);
>
> return 0;
>}
>
>ThreadParams will include the data to be verified as well as a handle
>to send PostMessages and a shutdown event.

****
Note that a shutdown event makes sense only if it makes sense to have a thread block on a
loop through the validation. Otherwise, a BOOL variable is sufficient, and often best.

Because things like DNS checking are typically synchronous, you need to explore some of
the asynchronous address resolution methods (I've never used them, but they are there
somewhere...)

Note that if you have a lengthy validation that is required to pass before you can
continue, then it is often best to start it as early as possible (e.g., as soon as the IP
address is "stable" in the input control) so that perhaps it is completed by the time the
user gets to the end of the wizard sequence. And if not, you would put up a modal dialog
saying "Validating input parameters..." with some kind of indicator (not a progress bar
because you don't know how long it will take, but a spinning wheel or something) so the
user knows what the delay is. If you have a "Cancel" button on this dialog, it puts you
back in the last page waiting for you to OK again (but note you don't necessarily cancel
the background validation, which can proceed concurrently)
joe
****


>
>
>> -Upon completion of the validation, the validation thread does a PostMessage back to the
>> main thread; for example, WPARAM or LPARAM can be used to indicate the result
>> - A handler for the above message deals with reporting this to the user
>>
>> See my essay on thread shutdown, where I talk about deferring closing a window; the basic
>> idea is that you ALWAYS fail the closing of the window, spin off the thread, and based on
>> validation results, either complete the closing of the window or do nothing
>
>I will have a look about this subject.
>
>
>After the verification I will send the map with the values back to the
>mainthread - and if there were no errors during the verification - the
>mainthread / document will set these values for the network settings,
>the serial port settings.... in the xmlfile. If everthing was
>successfull I will get back to the dialog (wizard).

****
But why return to the dialog? Presumably, you have just done everything it could be
asking of the user.
****


>
>I`m not sure if it makes sence to add a modal dialog when the user
>presses the ok-button; because apart from the verification of the
>network settings, all verifications will take only a short time, so
>that the user will see a flickering dialog.... or the user has to
>click the okbutton on the waiting-dialog,which will show him that all
>changes were made or not...

****
This is a judgment call, and yes, it is annoying to see a dialog flash up and disappear. I
used a trick, once. I guaranteed, via a timer, that the dialog would take no less than 5
seconds, even if validation succeeded instantly.


joe
****
>
>best regards
>Hans

Joseph M. Newcomer

unread,
Nov 14, 2010, 7:10:56 PM11/14/10
to
GetActiveWindow is a Really Bad Idea, and in any case, there is no reason to use
::PostMessage as you did; if you wanted to post a message to the active window, you would
do
CWnd * wnd = GetActiveWindow();
if(wnd != NULL)
wnd->PostMessage(UWM_VERIFY_END);

but GetActiveWindow is not a really good idea because it presumes you know what the
current active window is. The number of times I've had to repair code like this is very
high.
joe

0 new messages