Solved

Command routing of certain ActiveX webbrowser control event

Posted on 2004-04-22
25
616 Views
Last Modified: 2013-11-20
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
Comment
Question by:mrwad99
  • 13
  • 12
25 Comments
 
LVL 44

Expert Comment

by:AndyAinscow
ID: 10888466
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
 
LVL 19

Author Comment

by:mrwad99
ID: 10888504
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
 
LVL 44

Expert Comment

by:AndyAinscow
ID: 10888607
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
 
LVL 19

Author Comment

by:mrwad99
ID: 10888786
>> ((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
 
LVL 44

Expert Comment

by:AndyAinscow
ID: 10888850
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
 
LVL 19

Author Comment

by:mrwad99
ID: 10888892
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
 
LVL 44

Expert Comment

by:AndyAinscow
ID: 10888933
Ah, you can't identify if it is the commandstatechange message in the OnCmdMsg.  Is that the problem?
0
 
LVL 19

Author Comment

by:mrwad99
ID: 10888943
Bang on.
0
 
LVL 44

Expert Comment

by:AndyAinscow
ID: 10888979
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
 
LVL 44

Expert Comment

by:AndyAinscow
ID: 10888981
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
 
LVL 19

Author Comment

by:mrwad99
ID: 10889233
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
 
LVL 19

Author Comment

by:mrwad99
ID: 10906879
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
Top 6 Sources for Identifying Threat Actor TTPs

Understanding your enemy is essential. These six sources will help you identify the most popular threat actor tactics, techniques, and procedures (TTPs).

 
LVL 44

Expert Comment

by:AndyAinscow
ID: 10915778
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
 
LVL 44

Expert Comment

by:AndyAinscow
ID: 10915786
Ok. had a look.  the question is closed and I don't see anything obviously not answered.
0
 
LVL 19

Author Comment

by:mrwad99
ID: 10921144
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
 
LVL 44

Expert Comment

by:AndyAinscow
ID: 10925722
I don't know exactly what you mean because that calls the CDialog function and has nothing to do with your derived class.
0
 
LVL 19

Author Comment

by:mrwad99
ID: 10926833
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
 
LVL 44

Expert Comment

by:AndyAinscow
ID: 10926920
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
 
LVL 19

Author Comment

by:mrwad99
ID: 10927031
>> 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
 
LVL 44

Expert Comment

by:AndyAinscow
ID: 10927394
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
 
LVL 19

Author Comment

by:mrwad99
ID: 10927437
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
 
LVL 44

Expert Comment

by:AndyAinscow
ID: 10928658
Put a breakpoint, step into the call stack, see what class it comes from
0
 
LVL 19

Author Comment

by:mrwad99
ID: 10931552
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
 
LVL 44

Accepted Solution

by:
AndyAinscow earned 250 total points
ID: 10937072
As long as it works be pragmatic - leave it alone.

If it aint broken, don't fix it!
0
 
LVL 19

Author Comment

by:mrwad99
ID: 10937175
(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

What Is Threat Intelligence?

Threat intelligence is often discussed, but rarely understood. Starting with a precise definition, along with clear business goals, is essential.

Join & Write a Comment

Suggested Solutions

Introduction: Ownerdraw of the grid button.  A singleton class implentation and usage. Continuing from the fifth article about sudoku.   Open the project in visual studio. Go to the class view – CGridButton should be visible as a class.  R…
Introduction: Database storage, where is the exe actually on the disc? Playing a game selected randomly (how to generate random numbers).  Error trapping with try..catch to help the code run even if something goes wrong. Continuing from the seve…
This video will show you how to get GIT to work in Eclipse.   It will walk you through how to install the EGit plugin in eclipse and how to checkout an existing repository.
Access reports are powerful and flexible. Learn how to create a query and then a grouped report using the wizard. Modify the report design after the wizard is done to make it look better. There will be another video to explain how to put the final p…

707 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

19 Experts available now in Live!

Get 1:1 Help Now