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

TEventDispatcher: Needl help with creating event sink for IHTMLElementEvents2

5 views
Skip to first unread message

James O'Brien

unread,
Feb 9, 2005, 12:23:50 AM2/9/05
to

Hello,

I'm having trouble creating an event sink for "HTMLElementEvents2" type
events using TEventDispatcher class. I was able to use TEventDispatcher
class to create an event sink for "HTMLDocumentsEvents2" and thought it
would be simple enough to do the same for "HTMLElementEvents2", but the
ConnectEvents() method is failing

Below is my class declaration followed by the Connect() function which in
turn calls ConnectEvents(). I've verified that th [IHTMLElement *pElement]
being passed in to Connect method is valid. From Borland's documentation, I
am assuming that the search for the correct connection point is being done
by TEventDispatcher class and that I wouldn't need to do this manually.
This seemed to be the case when I created an event sink for
"HTMLDocumentsEvents2".

Also, docs say that if ConnectEvents() fails it returns an error code, but
it gives no indication of how to interpret this code. Does anyone have a
suggestion about this?

Thanks.
James O'Brien

class ElementCTRL: public TEventDispatcher<ElementCTRL,
&DIID_HTMLElementEvents2>
{
private:
IHTMLElement2 *Server;
void __fastcall HandleEvents(DISPID id, TVariant *params);

protected:

//overloaded from TEventDispatcher.
HRESULT InvokeEvent(DISPID id, TVariant *params);

public:

ElementCTRL();
~ElementCTRL();

HRESULT Connect(IHTMLElement2 *pElement);
HRESULT Disconnect();
bool Connected();

//place event handler declarations here
void (__closure *OnMouseOut)(void);
void (__closure *OnMouseOver)(AnsiString*, AnsiString*);
void (__closure *OnMouseMove)(int, int);
void (__closure *OnKeyDown)(T_IHTMLElement&, T_IHTMLEventObj&);
void (__closure *OnContextMenu)(int);
void (__closure *OnFocus)(T_IHTMLElement&, T_IHTMLEventObj&);

};

//--------------------------------------------------------------------------
-----------

HRESULT ElementCTRL::Connect(IHTMLElement2 *pElement)
{
HRESULT hResult=S_FALSE;
Server = pElement;
if(Server)
hResult = ConnectEvents(Server);

return hResult;
}
//--------------------------------------------------------------------------
-


Remy Lebeau (TeamB)

unread,
Feb 9, 2005, 2:17:04 AM2/9/05
to

"James O'Brien" <obr...@niscnet.com> wrote in message
news:42099e61$1...@newsgroups.borland.com...

> Also, docs say that if ConnectEvents() fails it returns an error code,
> but it gives no indication of how to interpret this code.

Many error codes are defined in winerror.h

> Does anyone have a suggestion about this?

What value is actually being returned?

> HRESULT ElementCTRL::Connect(IHTMLElement2 *pElement)
> {
> HRESULT hResult=S_FALSE;
> Server = pElement;

You did not call AddRef() on the element.


Gambit


James O'Brien

unread,
Feb 9, 2005, 8:27:13 AM2/9/05
to
> > Also, docs say that if ConnectEvents() fails it returns an error code,
> > but it gives no indication of how to interpret this code.
>
> Many error codes are defined in winerror.h
>
> > Does anyone have a suggestion about this?
>
> What value is actually being returned?


#define E_NOINTERFACE _HRESULT_TYPEDEF_(0x80004002L)

> > HRESULT ElementCTRL::Connect(IHTMLElement2 *pElement)
> > {
> > HRESULT hResult=S_FALSE;
> > Server = pElement;
>
> You did not call AddRef() on the element.

This doesn't seem to make a difference. I didn't call AddRef() on the
element because
in examples I've come accross (inluding Microsoft), AddRef() is not called
either. I thought
referenced was incremented when you initially call QureryInterface for the
an object.

I added the following bit of code to explicitly locate the connection point
for "HTMLDocumentsEvents2"


IConnectionPointContainer* pCPC = NULL;
IConnectionPoint* pCP = NULL;

if(SUCCEEDED(pElement->QueryInterface(IID_IConnectionPointContainer,
(void**)&pCPC))){
if(SUCCEEDED(pCPC->FindConnectionPoint(DIID_HTMLElementEvents2,
&pCP))){

hResult=S_OK;
pCP->Release();
}
pCPC->Release();
}

The call "QueryInterface" succeeds, the call to "FindConnectionPoint" fails.
At least it's consistent with the error I'm getting, but it's not
encouraging.

Would an interface not being available for a particular HTML element have
anything to do with IE security/privacy settings?


James O'Brien


Remy Lebeau (TeamB)

unread,
Feb 9, 2005, 1:48:42 PM2/9/05
to

"James O'Brien" <obr...@niscnet.com> wrote in message
news:420a0faf$1...@newsgroups.borland.com...

> #define E_NOINTERFACE _HRESULT_TYPEDEF_(0x80004002L)

Then the element in question does not support the requested event interface
and/or the requested connection point.

> I didn't call AddRef() on the element because in examples I've come
> accross (inluding Microsoft), AddRef() is not called either.

Every time you hold on to an interface, you need to call AddRef(). When you
are done holding on to the interface, you need to call Release(). You must
follow proper these rules or else the interface's reference counting may get
out of sync.

> I thought referenced was incremented when you initially call
QureryInterface
> for the an object.

It is. But only if QueryInterface() succeeds in returning an interface to
begin with. If QueryInterface() fails, the reference count is unchanged.
But your TEventDispatcher code is still holding on to the original element
interface anyway.

> The call "QueryInterface" succeeds, the call to "FindConnectionPoint"
fails.

Then the element does not support HTMLElementEvents2 to begin with. You can
use IConnectionPointContainer::EnumConnectionPoints() to find out what
connection points the elements actually supports.

What kind of element are you trying to get events from in the first place?


Gambit


James O'Brien

unread,
Feb 9, 2005, 2:26:01 PM2/9/05
to
> What kind of element are you trying to get events from in the first place?
"IHTMLElement"
Specifically <INPUT>

I'm able to retrieve pointers to these elements with the code listed below.
"InputSink" is actually an array of type [ElementCTRL] ; the event
dispatcher I created to handle events of type DIID_HTMLElementEvents2. I'm
passing in a pointer of type IHTMLElement. to the event dispatcher. And
before you ask, I did try
using DIID_HTMLElementEvents as connection point instead of
DIID_HTMLElementEvents2, but got the same result.

James O'Brien

//------------------------------------------------------------------
void TDHTMLForm::DocComplete(T_IHTMLDocument2 &HTMLDoc)
{
long i, lngth;

HRESULT hResult;

AnsiString Tag;
BSTR bstr;

IHTMLElementCollection *pAll = NULL;

if(SUCCEEDED(HTMLDoc->get_all(&pAll))){

IDispatch *pElementDisp;

pAll->get_length(&lngth);

TVariant index, event;
IHTMLElement *pElement;

InputCnt=0;
for(i=0; i<lngth; i++){

index = i;
hResult = pAll->item( VARIANT(index), VARIANT(index),
&pElementDisp);
pElementDisp->QueryInterface(IID_IHTMLElement, (LPVOID*)&pElement);

pElement->get_tagName(&bstr);
Tag = bstr;
::SysFreeString(bstr);

if( !Tag.AnsiCompareIC("input") ){

InputSink[InputCnt].Connect(pElement);
InputCnt++;

}
else
pElement->Release();


pElementDisp->Release();


}
pAll->Release();

}

}
//---------------------------------------------------------------------------


Remy Lebeau (TeamB)

unread,
Feb 9, 2005, 3:15:27 PM2/9/05
to

"James O'Brien" <obr...@niscnet.com> wrote in message
news:420a...@newsgroups.borland.com...

> "IHTMLElement"
> Specifically <INPUT>

The INPUT element does not have any events to begin with. What EXACTLY are
you trying to accomplish in the first place?

> I'm able to retrieve pointers to these elements with the code listed
below.

That code has problems. See below.

> long i, lngth;

You did not intialize lngth with an initial value.

> pAll->get_length(&lngth);

You did not check get_length() for failure.

> index = i;
> hResult = pAll->item( VARIANT(index), VARIANT(index),
> &pElementDisp);

You don't need the casts as TVariant derives from VARIANT. Also, you are
not specifying the correct index for the second parameter. You need to use
a value of 0, not the loop index. Also, you are not checking the return
value of get_item() before accessing the returned interface. If get_item()
fails, your code will be accessing an invalid pointer.

> pElement->get_tagName(&bstr);
> Tag = bstr;
> ::SysFreeString(bstr);

You can use a WideString instead of a BSTR to simply that code:

WideString bstr


pElement->get_tagName(&bstr);
Tag = bstr;

> if( !Tag.AnsiCompareIC("input") ){

If you are using BCB6, you can then use WideSameText() instead and get rid
of the AnsiString altogether:

if( WideSameText(bstr, L"input")

> InputSink[InputCnt].Connect(pElement);
> InputCnt++;
>
> }
> else
> pElement->Release();

You are only releasing pElement if it is not an "input" tag. You should be
releasing it always, and make Connect() call AddRef() internally. Don't
forget to make the TEventDispatcher call Release() when it is no longer
needs the element.


Gambit


James O'Brien

unread,
Feb 9, 2005, 5:06:22 PM2/9/05
to
Hello Again,

> The INPUT element does not have any events to begin with. What EXACTLY
> are
> you trying to accomplish in the first place?

What do you mean INPUT elements don't have events? If I have an editbox
<input type="text> on an HTML page, you can type text into it , you can move
the mouse cursor over it, you select text within the editbox. All of which
should result in events being fired.

My goal is to be able to track the caret position within an editbox<input
type="text> as the user is typing. I'm was able to do this by responding to
document level events (HTMLDocumentEvents2 ), but I didn't have the ability
to know when an editbox goes in and out of focus. To do this, I need to
respond to events for to the editbox itself. To do this, I need to
connect an event dispatcher based on DIID_HTMLElementEvents2 to one of the
following objects:

IHTMLElement
IHTMLElement2


James O'Brien


Remy Lebeau (TeamB)

unread,
Feb 9, 2005, 5:57:06 PM2/9/05
to

"James O'Brien" <obr...@niscnet.com> wrote in message
news:420a895f$1...@newsgroups.borland.com...

> If I have an editbox <input type="text> on an HTML page, you can
> type text into it , you can move the mouse cursor over it, you select
> text within the editbox. All of which should result in events being fired.

<input type="text"> uses HTMLInputTextElementEvents/2, not
HTMLElementEvents/2.

<input type="image"> uses HTMLInputImageEvents/2, not HTMLElementEvents/2.

<input type="file"> uses HTMLInputFileElementEvents/2, not
HTMLElementEvents/2.

In fact, most HTML elements in general have specialized connection points of
their own rather than using HTMLElementEvents/2 directly. Refer to the
following list for more details:

MSHTML Event DispInterfaces

http://msdn.microsoft.com/workshop/browser/mshtml/reference/events/events.asp

> My goal is to be able to track the caret position within an
> editbox <input type="text> as the user is typing.

Use DIID_HTMLInputTextElementEvents/2.

> To do this, I need to connect an event dispatcher based on
> DIID_HTMLElementEvents2

No, you do not. That is not the correct DIID to use in the first place.
You already verified that by proving the connection point for that DIID does
not exist to begin with.


Gambit


James O'Brien

unread,
Feb 10, 2005, 3:31:40 PM2/10/05
to
Hello

Before reading your last e-mail, out of despiration I tried using
DIID_HTMLInputTextElementEvents, and it did work.

I've been looking at the same documentation you suggested, only on DVD. I
guess my thinking was that the more specialized events (input, image, button
would filter up to the more general. When I was responding to document
level events, I could always determine what object in the document
actually fired the event.

Anyway, thanks for the info.

James O'Brien


"Remy Lebeau (TeamB)" <no....@no.spam.com> wrote in message
news:420a9478$1...@newsgroups.borland.com...

Remy Lebeau (TeamB)

unread,
Feb 10, 2005, 4:13:02 PM2/10/05
to

"James O'Brien" <obr...@niscnet.com> wrote in message
news:420bc4ad$1...@newsgroups.borland.com...

> I've been looking at the same documentation you suggested, only
> on DVD. I guess my thinking was that the more specialized events
> (input, image, button would filter up to the more general.

That is not how connect points work.


Gambit


0 new messages