[Okta Webinar] Learn how to a build a cloud-first strategyRegister Now

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 632
  • Last Modified:

Command routing of certain ActiveX webbrowser control event

Hello..

I have an MDI app that uses a dialogue in its view.  In this dialogue is an ActiveX webbrowser control.  Now, I handle all of the messages pertaining from this control in the dialogue class, eg OnBeforeNavigate etc, but there is one message I need to handle in my view class.

This message is OnCommandStateChange; I have toolbar buttons linked to the browser's ability to navigate forwards or backwards that I want to enable/disable accordingly.  Now I need to handle this message in the view class because a previous question here informed me that it would be a lot of trouble to route messages to update toolbar buttons to the dialogue class !

Here is what I have so far:

BOOL CContainerDlg::OnCmdMsg (UINT nID, int nCode, void* pExtra,
      AFX_CMDHANDLERINFO* pHandlerInfo)
{

// Forward ActiveX control events to the dialog's parent.
#ifndef _AFX_NO_OCC_SUPPORT

      if (nCode == CN_EVENT)
            return GetParent ()->OnCmdMsg (nID, nCode, pExtra, pHandlerInfo);

#endif // !_AFX_NO_OCC_SUPPORT

      return CDialog::OnCmdMsg (nID, nCode, pExtra, pHandlerInfo);
}

So this is forwarding all ActiveX messages to the view class, which is not want I want to do: I want to forward the OnCommandStateChange message only !

I know I could simply test to see if the message was handled in the view class, and if it is not then handle it in the dialogue, but I was hoping there was a way I could test to see if the the message coming into the above function was the one I wanted to save forwarding *all* messages.  Is there ?  

I figured the parameters to OnCmdMsg would be useful, but I cannot see that they are.  

There is more info about CommandStateChanged at http://msdn.microsoft.com/library/default.asp?url=/workshop/browser/webbrowser/reference/ifaces/dwebbrowserevents2/commandstatechange.asp.


TIA !
0
mrwad99
Asked:
mrwad99
  • 13
  • 12
1 Solution
 
AndyAinscowCommented:
If your dialog is modal (DoModal rather than Create) then your view should be disabled whilst the dialog is in the modal loop - so passing the message to the view is probably not going to be of use.

What might be simplest to do is trap this message along with the others in your dialog.  Then just for this message call a function in the view directly from the dialog.  
eg.
m_pView->DoSomething();
where m_pView is a member var of the dialog which is pointer to the view controlling the toolbar.
0
 
mrwad99Author Commented:
Hi  AndyAinscow, thanks for the response.

I think I need to reclarify "I have an MDI app that uses a dialogue in its view"...

http://msdn.microsoft.com/msdnmag/issues/0600/Wicked/

See, the view *is* a dialogue....
0
 
AndyAinscowCommented:
OK.
The dialog/view is embedded in a FrameWnd.  Put the handlers for the toolbar buttons into that frame.  
Keep doing what you currently do in the dialog and then for this message

((CChildFrame*)GetParentFrame())->DoSomething();
0
Concerto Cloud for Software Providers & ISVs

Can Concerto Cloud Services help you focus on evolving your application offerings, while delivering the best cloud experience to your customers? From DevOps to revenue models and customer support, the answer is yes!

Learn how Concerto can help you.

 
mrwad99Author Commented:
>> ((CChildFrame*)GetParentFrame())->DoSomething();

I am not sure what you mean by that.  I don't think we are clear on what I am asking; let me re-explain:

The webbrowser control I have embedded in my dialogue (which as you have seen from the example in the link I posted) generates varying messages.  These include OnBeforeNavigate2, OnDownloadBegin, OnDownloadComplete..... The browser can navigate backwards and forwards through its history via the functions GoBack() and GoForwards() respectively.  I have linked these commands to two toolbar buttons.  Now, if there is no page to navigate back to, I would like to disable the back button (just like IE does) to inform the user of this fact: ditto for the forward button also.

The message that lets me do this is OnCommandStateChange, which is handled via

      ON_EVENT(CContainerDlg, IDC_EXPLORER1, 105 /* CommandStateChange */, OnCommandStateChangeExplorer1, VTS_I4 VTS_BOOL)

where IDC_EXPLORER1 is the ID of the webbrowser control.  The message is handled in my function OnCommandStateChangeExplorer1() hence.

All of the other webbrowser messages are handled in the dialogue class that contains the control, but this particular message needs to be handled elsewhere (as you stated in the last question of mine you participated in - http:/Q_20958143.html - , it is difficult to enable/disable toolbar buttons in a dialogue class).  So I figured I would do it in the view; this seems to be as good a place as any to do it.  So the above function/message map macro are residing in my view now, and what I need to know is if there is any way I can, in OnCmdMsg that is in my dialogue class, determine if the message being handled *is this particular OnCommandStateChange message*.  If it is, I want to forward this to the view class, so it can be handled by the mentioned function, *Otherwise I want to leave it to be handled by the handlers in my dialogue class*.

See what I am after ?
0
 
AndyAinscowCommented:
I think I understand what you want.  Maybe if I put it in my words.
You are getting a message from your browser control - commandstatechange - the message could go to either your dialog or to your view.  You want to be able to tell if the view has handled it from the dialog.
Is that correct?
0
 
mrwad99Author Commented:
If I get that message generated by the webbrowser control, I want to forward it to the view because that is where the handler for it is, and needs to be to alter the toolbar buttons.  I originally thought I could do it via the paramters in OnCmdMsg...

BOOL CContainerDlg::OnCmdMsg (UINT nID, int nCode, void* pExtra,
     AFX_CMDHANDLERINFO* pHandlerInfo)
{
// Determine here if the message is the commandstatechange message, maybe via nID or nCode ??

... but could not figure out how.
0
 
AndyAinscowCommented:
Ah, you can't identify if it is the commandstatechange message in the OnCmdMsg.  Is that the problem?
0
 
mrwad99Author Commented:
Bang on.
0
 
AndyAinscowCommented:
I'll see if I can find out.  I don't know myself offhand.

It is handled in the CHTMLView class, maybe you could create a simple app and see if you can track it down ther.
0
 
AndyAinscowCommented:
I'll see if I can find out.  I don't know myself offhand.

It is handled in the CHTMLView class, maybe you could create a simple app and see if you can track it down ther.
0
 
mrwad99Author Commented:
At the link I posted in the original question there is a futher link:
http://msdn.microsoft.com/library/default.asp?url=/workshop/browser/webbrowser/reference/ifaces/dwebbrowserevents2/commandstatechange.asp

which gives some hex values, eg CSC_NAVIGATEFORWARD = 0x00000001

I was hoping there was something that could be done with numbers like this to identify the event, with all those that are in OnCmdMessage.

Appreciate the help.

>> It is handled in the CHTMLView class, maybe you could create a simple app and see if you can track it down ther

I dont want to track it down as such, I just need to know if there is a way of identifying it from within OnCmdMsg or otherwise.  Surely every command has an ID or something that can be picked out...?
0
 
mrwad99Author Commented:
AndyAinscow:  AlexFM commented on this one at another of my questions (http:/Q_20963870.html) and gave a reasonable solution there about setting flags in the dialogue class.  After consideration it turned out that this is the best way to handle this problem, as if I have several webbrowser controls all generating the commandstatechange message then the button states could be messed up, as I need to handle the message for the *currently active* dialogue only, hence set the button state depending on the state of the *currently active* dialogue only.

I have posted another query regarding this however at the above question, if you could answer that I can then split the points for this question between you and AlexFM.

Thanks very much !
0
 
AndyAinscowCommented:
So my first comment wasn't far off what you needed.

<as I need to handle the message for the *currently active* dialogue only, hence set the button state depending on the state of the *currently active* dialogue only.>

Have the flag in the view (only ONE) required instead of one per dialog.  You handle it's state when you change the dialog focus or the internal state of the dialog.

I'll have a look at the other post, Alex has probably answered that by now knowing how competant he is
0
 
AndyAinscowCommented:
Ok. had a look.  the question is closed and I don't see anything obviously not answered.
0
 
mrwad99Author Commented:
Ok, what I was asking in the other question was an explanation as to how

return CDialog::OnCmdMsg (nID, nCode, pExtra, pHandlerInfo);

contained within PreTranslateMessage manages to get the message handled by the ActiveX handlers in my derived (current) dialog class ?  I thought I had an idea but would like someone with your experience to explain it fully.

TIA !

This will be closed if you can answer that; since it is related to the solution that AlexFM has given.
0
 
AndyAinscowCommented:
I don't know exactly what you mean because that calls the CDialog function and has nothing to do with your derived class.
0
 
mrwad99Author Commented:
Ok this is some of the code from PreTranslateMessage that is contained in my dialogue class,which is embedded in the view.  This same dialogue class contains the ActiveX webbrowser component and the handlers for the ActiveX events.

// Forward ActiveX control events to the dialog's parent.
#ifndef _AFX_NO_OCC_SUPPORT

     if (nCode == CN_EVENT)
          if (GetParent ()->OnCmdMsg (nID, nCode, pExtra, pHandlerInfo))  ***
               return TRUE;

#endif // !_AFX_NO_OCC_SUPPORT

     return CDialog::OnCmdMsg (nID, nCode, pExtra, pHandlerInfo); ###

Now obviously *** is stating that if the message is handled in the view class, don't do anything else.  T

So am I right in thinking that if the view does *not* process the message, CDialog::OnCmdMsg (###) gets a crack at it ?  If so, how does this work ?  Does CDialog::OnCmdMsg find the handlers I have in my (derived) dialogue class and call the appropriate one ?  I think I am getting confused since CDialog does not contain any handlers for ActiveX events, so forwarding the message to this class cannot result in it getting handled...or can it ?

Thanks.
0
 
AndyAinscowCommented:
OK, I'll give it a stab but this is really getting deep into how MFC is coded.

The default function will take the message apart and call one or more virtual functions until one returns true to say it has been handled.  If none return true then the default function will return false to inform the function that called it that the message was not handled.

So, I think, the answer you require is it won't get handled.

0
 
mrwad99Author Commented:
>> So, I think, the answer you require is it won't get handled.

But that is what I am saying; if the view does not process the message then the message gets handled by the ActiveX handlers in the current dialogue class.  So I am just wondering how this occurs when the only option remaining is

return CDialog::OnCmdMsg (nID, nCode, pExtra, pHandlerInfo);

?
0
 
AndyAinscowCommented:
OK - it is being handled. How?

The message isn't being handled BUT it was being generated from the control so the control ITSELF handles it as nothing else has handled it.
0
 
mrwad99Author Commented:
If the control is doing the handling then how come I get, for example, on receipt of a OnBeforeNavigate message, my OnBeforeNavigateExplorer member function handler being called ?  I know it is being called since I can put a messagebox call there:

void CMyDlg::OnBeforeNavigateExplorer(...)
//...
MessageBox("Blah blah");
}

Which is where my confusion lies !

TIA
0
 
AndyAinscowCommented:
Put a breakpoint, step into the call stack, see what class it comes from
0
 
mrwad99Author Commented:
OK, what actually happens is the following:

(START) CContainerDlg::OnCmdMsg (My dialogue class) -> CDialog::OnCmdMsg  -> CCmdTarget::OnCmdMsg -> COccManager::OnEvent -> CCmdTarget::OnEvent -> _AfxDispatchCall -> CContainerDlg::OnBeforeNavigate2Explorer1 (END)

So is this ok, or is there a better way I could route the messages that the browser generates to the handlers in my dialog class ?

TIA !
0
 
AndyAinscowCommented:
As long as it works be pragmatic - leave it alone.

If it aint broken, don't fix it!
0
 
mrwad99Author Commented:
(The "used" solution to this question was posted at http:/Q_20963870.html by AlexFM.  This question has been closed and points awarded to AndyAinscow for a) attempts to solve the original question b) help in sorting out related queries, listed towards the end of this question).

Thanks for the help Andy.
0

Featured Post

Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

  • 13
  • 12
Tackle projects and never again get stuck behind a technical roadblock.
Join Now