以MSHTML中的HTMLElementEvents2接口为例,每个接口 EventMethods传递一个pEvtObj参数,如
HTMLElementEvents2 = dispinterface
[...]
function onclick(const pEvtObj: IHTMLEventObj): WordBool; dispid -600;
标识哪个元素称为事件。所以, 如果你定义一个来自TInterfacedObject的类,它实现了 HTMLElementEvents2接口,在实现的事件方法中,您可以识别 哪个特定的HTML元素称为事件处理程序,因此访问其成员。
能够识别调用该事件的调用者对象是非常好的 处理程序实例从中接收事件调用的地方非常重要 多个调用者(例如,当处理程序附加到MSHTML示例中的多个HTML元素时)。
这种实现COM事件处理程序的方法工作正常,但在源代码中有点冗长 术语,因为它需要定义实现事件接口中每个事件的方法。
我假设有一种替代的,更简洁的实现事件处理程序的方法 在OleCtrls.Pas中的TEventDispatch类,它允许您附加处理程序 单个事件 - 请参阅我对q的回答 Detect when the active element in a TWebBrowser document changes
该答案中的技术问题是我无法在Invoke实现中看到识别调用者对象的方法,而我的问题是,这可以做到,如果是这样,怎么做?
我已经尝试过观察传递给答案的Invoke的无类型Params参数, 通过这样的代码:
function TEventObject.Invoke(DispID: Integer; const IID: TGUID;
LocaleID: Integer; Flags: Word; var Params; VarResult, ExcepInfo,
ArgErr: Pointer): HResult;
var
vPDispParams : PDispParams;
begin
vPDispParams := PDispParams(@Params);
[...]
但是vPDispParams的rgvarg成员^(我希望包含pEvtObj 参数)不包含任何元素,其cArgs为零。
我对链接q的回答中的代码是我所要求的MCVE。
答案 0 :(得分:3)
在@IgorTandetnik的评论的帮助下,我非常感激,我找到了解决这个问题的方法。
在链接的答案中,我使用了一个有缺陷的EventObject赋值给HTML Input元素,就像这样
var
V : OleVariant;
E : IHtmlElement;
V := Doc.getElementById('input1');
E := IDispatch(V) as IHtmlElement;
// Create an EventObject as per the linked answer
DocEvent := TEventObject.Create(Self.AnEvent, True) as IDispatch;
E.onclick := DocEvent;
在这样做时,我忽略了一个事实,即IHTMLElement有一个OnClick属性,而且它是我分配DocEvent的,而不是与它相关的一些想象的Events接口。
当我使用ConnectionPoint替换E.onclick := DocEvent
时,就像这样
ITE := IDispatch(V) as IHtmlInputTextElement;
Assert(ITE <> Nil);
CPC := ITE as IConnectionPointContainer;
Assert(CPC <> Nil);
OleCheck(CPC.FindConnectionPoint(HTMLInputTextElementEvents2, CP));
OleCheck((CP as IConnectionPoint).Advise(DocEvent, Cookie));
,然后DocEvent的.Invoke方法工作正常。特别是,我可以访问HTMLInputTextElementEvents2.OnClick方法的IEvtObj 使用如下代码:
function TEventObject.Invoke(DispID: Integer; const IID: TGUID;
LocaleID: Integer; Flags: Word; var Params; VarResult, ExcepInfo,
ArgErr: Pointer): HResult;
[...]
begin
vPDispParams := PDispParams(@Params);
V := OleVariant(vPDispParams^.rgvArg^[0]);
IDisp := IDispatch(V);
if Supports(IDisp, IHTMLEventObj, IEvtObj) then begin
IHE := IEvtObj.srcElement;
IHE.QueryInterface(IHtmlInputTextElement, ITE);
end;
所以,神秘解决了。我的问题是一个XY问题 - 我认为我需要识别事件的调用者,而如果我使用FindConnectionPoint为我想要使用的事件接口设置事件处理,那么需要#n&# 39; t已经出现。