您的位置:首页 > Web前端 > HTML

强大的文章必须转载保留 Handling HTML Element Events

2013-01-04 13:58 399 查看


Handling HTML Element Events

9 out of 9 rated this helpful - Rate
this topic

The HTMLElementEvents2 interface is an event sink interface that enables an application to receive events for HTML elements. Your
custom application can receive these events, which are fired in response to user actions on HTML elements, when hosting the WebBrowser
Control or automating Windows Internet Explorer.

The HTMLElementEvents2 interface is introduced and the steps required to receive notification of HTML element events from the browser are described, using Microsoft Visual Studio 5 or later.

It is assumed that a Microsoft Foundation Classes (MFC) application is hosting the WebBrowser Control, or launching Internet Explorer.

This article is divided into the following sections.

Accessing the DHTML Object Model
Accessing an Element on the Page
Receiving Element Events
Handling Events using MFC
Handling Events using ATL
Related Topics


Accessing the DHTML Object Model

The IWebBrowser2::Navigate2 method of the IWebBrowser2 interface
allows you to navigate the browser to a URL. Once an HTML page is loaded, you can access the HTML elements through the Dynamic HTML (DHTML) Object Model.

The DHTML Object Model is used to access and manipulate the contents of an HTML page and is not available until the page is loaded. Your application determines that the page is loaded by handling the DWebBrowserEvents2::DocumentComplete event
of the WebBrowser Control. This event may be fired once for each frame in the page, and once when the top frame of the document is loaded. You can determine if theDWebBrowserEvents2::DocumentComplete event is for the top frame
by comparing the IDispatch interface pointer passed by this event with that of the WebBrowser Control.

This sample handler code for the DWebBrowserEvents2::DocumentComplete event demonstrates how to determine if this event is for the top frame, which indicates that the HTML page has loaded. This sample also demonstrates how to create a stream
from a block of memory—in this case a string that contains the HTML content to be displayed. The variable
m_pBrowser
contains the IWebBrowser2 interface pointer obtained from the WebBrowser Control.

void CMyClass::DocumentComplete(LPDISPATCH pDisp, VARIANT* URL)
{
    HRESULT hr;
    IUnknown* pUnkBrowser = NULL;
    IUnknown* pUnkDisp = NULL;
    IDispatch* pDocDisp = NULL;
    IHTMLDocument2* pDoc = NULL;

    // Is this the DocumentComplete event for the top frame window?
    // Check COM identity: compare IUnknown interface pointers.
    hr = m_pBrowser->QueryInterface(IID_IUnknown, (void**)&pUnkBrowser);

    if (SUCCEEDED(hr))
    {
        hr = pDisp->QueryInterface(IID_IUnknown, (void**)&pUnkDisp);

        if (SUCCEEDED(hr))
        {
            if (pUnkBrowser == pUnkDisp)
            {
                // This is the DocumentComplete event for the top frame.
                // This page is loaded, so we can access the DHTML Object Model.
                hr = m_pBrowser->get_Document(&pDocDisp);

                if (SUCCEEDED(hr))
                {
                    // Obtained the document object.
                    pDocDisp->QueryInterface(IID_IHTMLDocument2, (void**)&pDoc);
                    if (SUCCEEDED(hr))
                    {
                        // Obtained the IHTMLDocument2 interface for the document object
                        ProcessDocument(pDoc);
                    }

                    pDocDisp->Release();
                }
            }

            pUnkDisp->Release();
        }

        pUnkBrowser->Release();
    }
}


The IWebBrowser2::get_Document property on the WebBrowser Control retrieves the document object
that represents the DHTML Object Model for the top frame.


Accessing an Element on the Page

Using the IHTMLDocument2 interface pointer, you can request a collection of all elements in the HTML document through the all property.

void CMyClass::ProcessDocument(IHTMLDocument2* pDoc)
{
    IHTMLElementCollection* pElemColl = NULL;

    hr = pDoc->get_all(&pElemColl);
    if (SUCCEEDED(hr))
    {
        // Obtained element collection.
        ProcessElementCollection(pElemColl);
        pElemColl->Release();
    }
}


The all property returns a collection of all the HTML elements on the page through an IHTMLElementCollection interface
pointer. You can use theIHTMLElementCollection interface to call the item method and pass the name or id of
an element as a parameter, as shown in the following code.
Note The item method will return a collection if there is more than one element with the specified name or id. To prevent a collection from being returned, provide an index as the second
parameter of item to specify which element should be returned.

void CMyClass::ProcessElementCollection(IHTMLElementCollection* pElemColl)
{
    IDispatch* pElemDisp = NULL;
    IHTMLElement* pElem = NULL;
    _variant_t varID("myID", VT_BSTR);
    _variant_t varIdx(0, VT_I4);

    hr = pElemColl->item(varID, varIdx, &pElemDisp);

    if (SUCCEEDED(hr))
    {
        hr = pElemDisp->QueryInterface(IID_IHTMLElement, (void**)&pElem);

        if (SUCCEEDED(hr))
        {
            // Obtained element with ID of "myID".
            ConnectEvents(pElem);
            pElem->Release();
        }

        pElemDisp->Release();
    }
}


If you are working with HTML tags of a specific type, such as a tags, the IHTMLElementCollection::tags method
returns a collection of all the elements that have the requested HTML tag name, also through an IHTMLElementCollection interface pointer.


Receiving Element Events

Each element in the DHTML Object Model supports an outgoing HTMLElementEvents2 interface. This interface defines the events that an HTML element can fire. You implement this interface to provide an event sink, which is a Component
Object Model (COM) object that implements an outgoing interface and is used as the mechanism for firing events.
Note Interfaces implemented by a server usually have their methods called by the client, but to fire an event, the server calls the respective method on the client event sink. These interface are called outgoing interfaces.
A COM object that implements an outgoing interface is also known as a connectable object.

The following steps are required to receive events from an outgoing interface:

Implement the event sink.

The event sink implements the appropriate outgoing interface and methods. Internet Explorer event interfaces are dispinterfaces, so calls to event methods are made through IDispatch::Invoke.
This means that you only need to implement the IDispatch interface to handle events.

Determine if the server is a connectable object.

Call QueryInterface to retrieve a pointer to the IConnectionPointContainer interface.

Find the appropriate connection point.

Call the IConnectionPointContainer::FindConnectionPoint method to find the connection point you need. For Internet Explorer WebBrowser
Control
events, such as DWebBrowserEvents2::DocumentComplete, this is DWebBrowserEvents2. For element events, this is HTMLElementEvents2. You can also call the IConnectionPointContainer::EnumConnectionPoints to
enumerate through all the connection points a server supports.

Advise the connection point that you want to receive events.

Using the IConnectionPoint interface pointer returned in the previous step, call IConnectionPoint::Advise,
passing the IUnknown interface pointer of your event sink.

Note The connectable object will use the IUnknown interface pointer to query the client for the event sink interface. If the event sink does not support the outgoing interface, Internet Explorer will query
the client for the IDispatch interface.

When you no longer want to receive events, you can call the IConnectionPoint::Unadvise method, passing the cookie you received
from the call to IConnectionPoint::Advise.

The following sample code demonstrates how to begin receiving HTML element events for an element on an HTML page.

void CMyClass::ConnectEvents(IHTMLElement* pElem)
{
    HRESULT hr;
    IConnectionPointContainer* pCPC = NULL;
    IConnectionPoint* pCP = NULL;
    DWORD dwCookie;

    // Check that this is a connectable object.
    hr = pElem->QueryInterface(IID_IConnectionPointContainer, (void**)&pCPC);

    if (SUCCEEDED(hr))
    {
        // Find the connection point.
        hr = pCPC->FindConnectionPoint(DIID_HTMLElementEvents2, &pCP);

        if (SUCCEEDED(hr))
        {
            // Advise the connection point.
            // pUnk is the IUnknown interface pointer for your event sink
            hr = pCP->Advise(pUnk, &dwCookie);

            if (SUCCEEDED(hr))
            {
                // Successfully advised
            }

            pCP->Release();
        }

        pCPC->Release();
    }
}


The following sample code demonstrates how you would detect the firing of an HTMLElementEvents2::onclick event in your implementation
ofIDispatch::Invoke.

STDMETHODIMP CEventSink::Invoke(DISPID dispidMember,
                                REFIID riid,
                                LCID lcid,
                                WORD wFlags,
                                DISPPARAMS* pdispparams,
                                VARIANT* pvarResult,
                                EXCEPINFO* pexcepinfo,
                                UINT* puArgErr)
{
    switch (dispidMember)
    {
        case DISPID_HTMLELEMENTEVENTS2_ONCLICK:
        OnClick();
        break;

        default:
        break;
    }

    return S_OK;
}



Handling Events using MFC

The MFC CCmdTarget class implements the IDispatch interface, which means that any class derived
from this class can implement an event sink. The IDispatch feature requires a call to the CCmdTarget::EnableAutomation method.
The MFC AfxConnectionAdvise and AfxConnectionUnadvise functions
find a specified connection point and then advise or unadvise appropriately.
The DECLARE_DISPATCH_MAP, BEGIN_DISPATCH_MAP, DISP_FUNCTION, DISP_FUNCTION_ID and END_DISPATCH_MAP macros are used to map each event method to your event handler function.
When handling events from a Microsoft ActiveX control you are hosting in your MFC applications, use the DECLARE_EVENTSINK_MAP, BEGIN_EVENTSINK_MAP, ON_EVENT and END_EVENTSINK_MAP macros.
If you are hosting the WebBrowser Control on a dialog box, you can use the Microsoft Visual C++ ClassWizard to map events to event handlers.
The MFC CHtmlView class hosts the WebBrowser Control and provides overridable methods for the WebBrowser
Control
events.


Handling Events using ATL

When implementing an event sink using the Active Template Library (ATL), your object class will usually derive from the IDispatchImpl class, which provides a default implementation of the IDispatch interface.
You can the override the ATL implementation of the IDispatch::Invokemethod to handle events.
ATL provides two helper functions, AtlAdvise and AtlUnadvise, for advising
and unadvising a connection point. These find a specified connection point and then advise or unadvise appropriately.
You can also use the ATL IDispEventImpl and IDispEventSimpleImpl classes
and BEGIN_SINK_MAP, SINK_ENTRY, SINK_ENTRY_EX and END_SINK_MAP macros to implement an event sink. If you need to host the WebBrowser Control, you can use the ATL Object Wizard to create an HTML object.


Related Topics

The following articles provide information about the WebBrowser Control and MSHTML.

Reusing the WebBrowser Control
Using MFC to Host a WebBrowser Control
MSHTML Event DispInterfaces

The following articles provide information about Visual Studio.

Visual Studio Developer Center
HOWTO: Create a Sink Interface in MFC-Based COM Client
AtlSink Uses ATL to Create a Dispinterface Sink
SAMPLE: AtlEvnt.exe Creates ATL Sinks Using IDispEventImpl

The following articles provide information about COM.

The Component Object Model Specification
Inside OLE, 2nd Edition, by Kraig Brockschmidt (Microsoft Press)
Understanding ActiveX and OLE, by David Chappell (Microsoft Press)
Inside COM, by Dale Rogerson (Microsoft Press)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐