gpt4 book ai didi

delphi - 通过 IDispatch Invoke 实现识别 COM 事件的调用者

转载 作者:行者123 更新时间:2023-12-03 02:27:20 24 4
gpt4 key购买 nike

以MSHTML中的HTMLElementEvents2接口(interface)为例,每个EventMethods 传递了一个 pEvtObj 参数,如

HTMLElementEvents2 = dispinterface
[...]
function onclick(const pEvtObj: IHTMLEventObj): WordBool; dispid -600;

识别哪个元素调用了事件。所以,如果您定义一个继承自 TInterfacedObject 的类,该类实现了HTMLElementEvents2接口(interface),在实现的事件方法中,您可以识别哪个特定的 HTML 元素调用事件处理程序,从而访问其成员。

能够识别调用事件的调用者对象是非常好的当您的处理程序实例从以下位置接收事件调用时非常重要多个调用者(例如,当处理程序附加到 MSHTML 示例中的多个 HTML 元素时)。

这种实现 COM 事件处理程序的方法工作正常,但源代码有点冗长术语,因为它需要定义实现事件接口(interface)中每个事件的方法。

有一种替代的、更简洁的方法来实现事件处理程序,基于我假设在 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。

最佳答案

在 @IgorTandetnik 的评论的帮助下(我非常感谢他),我找到了这个问题的解决方案。

在链接的答案中,我使用了有缺陷的 EventObject 到 HTML 输入元素的分配,如下所示

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 接口(interface)。

当我使用 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 为我打算使用的事件接口(interface)设置事件处理,则不需要出现了。

关于delphi - 通过 IDispatch Invoke 实现识别 COM 事件的调用者,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35112998/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com