From: Bob Eaton on
I have some processing I want to do when the OK button of a
CPropertySheet/CPropertyPage dialog box is pressed. Unfortunately, (for
reasons that aren't clear to me) when the Apply button is pressed, the
default handler, OnApply, calls OnOK. This same method(s) are also called
when the OK button is pressed!?

My first question is, why does it do this?
If both methods are called when either button is pressed with no distinction
between them, I'm not clear what the benefit of having both is...

Second question is, is there any way in OnOK (or OnApply) to tell whether it
was called as a result of clicking the OK button versus the Apply button?

Thanks,
Bob


From: David Wilkinson on
Bob Eaton wrote:

> I have some processing I want to do when the OK button of a
> CPropertySheet/CPropertyPage dialog box is pressed. Unfortunately, (for
> reasons that aren't clear to me) when the Apply button is pressed, the
> default handler, OnApply, calls OnOK. This same method(s) are also called
> when the OK button is pressed!?
>
> My first question is, why does it do this?
> If both methods are called when either button is pressed with no distinction
> between them, I'm not clear what the benefit of having both is...
>
> Second question is, is there any way in OnOK (or OnApply) to tell whether it
> was called as a result of clicking the OK button versus the Apply button?
>
> Thanks,
> Bob
>
>

Bob:

Since CPropertyPage::OnApply and OnOK() are both virtual, you can
override them to do whatever you wish. But, personally, the first thing
I always do with a property sheet is remove the Apply button.

HTH,

David Wilkinson
From: Bob Eaton on
"David Wilkinson" <no-reply(a)effisols.com> wrote in message
news:eDJgmyn8FHA.2152(a)TK2MSFTNGP10.phx.gbl...
> Since CPropertyPage::OnApply and OnOK() are both virtual, you can override
> them to do whatever you wish. But, personally, the first thing I always do
> with a property sheet is remove the Apply button.

I guess I didn't make myself clear, then: You'd think that OnOK is called
when the OK button is clicked and that OnApply is called when the Apply
button is called, but this is not the case. The handler for either button is
OnApply, which calls OnOK. So that means that *both* methods are ultimately
called when either button is clicked.

So my question is, when I get OnApply, is there a way to tell whether it was
due to the OK button being clicked or the Apply button?

And strangely enough, I've overriden them both and they're *not* being
called... at least not in the sub-class I need... This much I'm pretty sure
is a compiler error (VS.Net 2003). Here's the situation:

My application is an ATL/MFC COM DLL. It uses MFC dynamically linked. Prior
to building my ATL/MFC COM DLL, I have a smallish shared project which
builds a few of the source files into a static library that is also set to
"Use MFC in a shared DLL". This static library, then is also linked as part
of multiple such ATL/MFC COM DLL projects.

My CPropertyPage sub-class, called CAutoConfigPropertyPage, is in the static
library as a base class that is also sub-classed in the different COM DLL
projects (e.g. CTecAutoConfigPropertyPage). It is in this latter class that
I want to override OnApply/OK to detect the click of the OK button. So
here's a picture of the situation:

MFC DLL virtual BOOL CPropertyPage::OnApply();

Static library: virtual BOOL CAutoConfigPropertyPage::OnApply();

COM DLL: virtual BOOL CTecAutoConfigPropertyPage::OnApply();

When the MFC framework gets the notification that either the OK or Apply
button has been pressed, it calls "OnApply", which in the above scenerio
*should* call the lowest (i.e. CTecAutoConfigPropertyPage) version. However,
it doesn't... Instead, it calls the static library's version (i.e.
CAutoConfigPropertyPage). And in fact, that version isn't really needed;
initially, I didn't have the CAutoConfigPropertyPage override at all, and
when that was the case, it didn't call my override at all, but went directly
to CPropertyPage::OnApply).

I tried taking the static library out of the situation so that the
CAutoConfigPropertyPage source was built directly in the COM DLL project
itself, but that didn't help. I've triple checked the declarations in the
CTecAutoConfigPropertyPage class and there's nothing wrong with it that
would cause the system to think it wasn't an override.

So here was my solution: Since the framework was willing to call the first
sub-class' implementation (in CAutoConfigPropertyPage in the static
library), I now override it there and call a pure virtual function which is
implemented in the CTecAutoConfigPropertyPage sub-class. I should mention
that it *had* to be a pure virtual function; a simple, non-pure virtual
function wouldn't work either!?

I've done these things before in other exe projects, so I believe the reason
for the bug is the existence of the COM DLL which uses MFC dynamically. I
bet if my COM object were implemented in an exe instead, or if it used MFC
statically, it would work.

But, all this was a side issue: My question still stands: is there a way to
tell during OnApply whether it was called as a result of the OK button being
called vs. the Apply button (and yes, I need both: there are things I need
to do which beg for the Apply button to persist).

Bob


From: Jeff Partch [MVP] on
"Bob Eaton" <pete_dembrowski(a)hotmail.com> wrote in message
news:OoDr6gu8FHA.1164(a)TK2MSFTNGP10.phx.gbl...
> "David Wilkinson" <no-reply(a)effisols.com> wrote in message
> news:eDJgmyn8FHA.2152(a)TK2MSFTNGP10.phx.gbl...
> So my question is, when I get OnApply, is there a way to tell whether it
was
> due to the OK button being clicked or the Apply button?

Does GetCurrentMessage return valid info in this context?
--
Jeff Partch [VC++ MVP]


From: David Wilkinson on
Bob Eaton wrote:

> "David Wilkinson" <no-reply(a)effisols.com> wrote in message
> news:eDJgmyn8FHA.2152(a)TK2MSFTNGP10.phx.gbl...
>
>>Since CPropertyPage::OnApply and OnOK() are both virtual, you can override
>>them to do whatever you wish. But, personally, the first thing I always do
>>with a property sheet is remove the Apply button.
>
>
> I guess I didn't make myself clear, then: You'd think that OnOK is called
> when the OK button is clicked and that OnApply is called when the Apply
> button is called, but this is not the case. The handler for either button is
> OnApply, which calls OnOK. So that means that *both* methods are ultimately
> called when either button is clicked.
>
> So my question is, when I get OnApply, is there a way to tell whether it was
> due to the OK button being clicked or the Apply button?
>

[snip]
>
> But, all this was a side issue: My question still stands: is there a way to
> tell during OnApply whether it was called as a result of the OK button being
> called vs. the Apply button (and yes, I need both: there are things I need
> to do which beg for the Apply button to persist).
>

Bob:

I'm not sure about your virtual function issue, but you're right, I did
misunderstand your original question, because I did think the naive
expectation about the relationship between the buttons and the handlers
was the reality.

It is this kind of thing that led me long ago to always remove the Apply
button. It also does not really make sense to me from a user
perspective, and I remember being confused by it when I first moved to
Windows from Mac. So have you considered doing this?

Otherwise, perhaps you have to catch the button clicks in the Property
Sheet. Then you really CAN do what you want. I actually use a modified
CPropertyPage base class in which I have

virtual BOOL OnOK();
virtual BOOL OnCancel();
virtual BOOL OnApply();
virtual BOOL OnHelp();

The base class versions of these functions returns TRUE;

BOOL CMyPropertySheet::OnCommand(WPARAM wParam, LPARAM lParam)
{
WORD code=HIWORD(wParam);
WORD nID=LOWORD(wParam);
if(code == BN_CLICKED)
{
switch (nID)
{
case IDOK:
if (!OnOK())
{
return 1;
}
break;
case IDCANCEL:
if(!OnCancel())
{
return 1;
}
break;
case ID_APPLY_NOW:
if(!OnApply())
{
return 1;
}
break;
case IDHELP:
if(!OnHelp())
{
return 1;
}
break;
}
}
return CPropertySheet::OnCommand(wParam, lParam);
}

Now in my actual derived class I can do anything I like.

HTH,

David Wilkinson