gpt4 book ai didi

c# - 如何连接 COM 事件调度程序?

转载 作者:行者123 更新时间:2023-11-30 14:26:21 25 4
gpt4 key购买 nike

VBIDE API 公开了非常神秘的 _dispVBComponentsEvents 接口(interface)(以及其他接口(interface)),看起来我可以用来捕获 VBE 中各种有趣事件的东西。 p>

所以我在一个类中实现了该接口(interface),该类旨在捕获事件并引发“正常”.net 事件供我的应用程序的其余部分处理,如下所示:

public class VBComponentsEventDispatcher : _dispVBComponentsEvents
{
public event EventHandler<DispatcherEventArgs<VBComponent>> ComponentAdded;
public void ItemAdded(VBComponent VBComponent)
{
OnDispatch(ComponentAdded, VBComponent);
}

public event EventHandler<DispatcherEventArgs<VBComponent>> ComponentRemoved;
public void ItemRemoved(VBComponent VBComponent)
{
OnDispatch(ComponentRemoved, VBComponent);
}

public event EventHandler<DispatcherRenamedEventArgs<VBComponent>> ComponentRenamed;
public void ItemRenamed(VBComponent VBComponent, string OldName)
{
var handler = ComponentRenamed;
if (handler != null)
{
handler.Invoke(this, new DispatcherRenamedEventArgs<VBComponent>(VBComponent, OldName));
}
}

public event EventHandler<DispatcherEventArgs<VBComponent>> ComponentSelected;
public void ItemSelected(VBComponent VBComponent)
{
OnDispatch(ComponentSelected, VBComponent);
}

public event EventHandler<DispatcherEventArgs<VBComponent>> ComponentActivated;
public void ItemActivated(VBComponent VBComponent)
{
OnDispatch(ComponentActivated, VBComponent);
}

public event EventHandler<DispatcherEventArgs<VBComponent>> ComponentReloaded;
public void ItemReloaded(VBComponent VBComponent)
{
OnDispatch(ComponentReloaded, VBComponent);
}

private void OnDispatch(EventHandler<DispatcherEventArgs<VBComponent>> dispatched, VBComponent component)
{
var handler = dispatched;
if (handler != null)
{
handler.Invoke(this, new DispatcherEventArgs<VBComponent>(component));
}
}
}

我希望像这样使用类:

var componentsEvents = new VBComponentsEventDispatcher();
componentsEvents.ComponentAdded += componentsEvents_ComponentAdded;
componentsEvents.ComponentActivated += componentsEvents_ComponentActivated;
//...
void componentsEvents_ComponentAdded(object sender, DispatcherEventArgs<VBComponent> e)
{
Debug.WriteLine(string.Format("Component '{0}' was added.", e.Item.Name));
}

void componentsEvents_ComponentActivated(object sender, DispatcherEventArgs<VBComponent> e)
{
Debug.WriteLine(string.Format("Component '{0}' was activated.", e.Item.Name));
}

但它不起作用,我没有得到调试输出,也没有命中断点。显然我不知道我在做什么。 MSDN 在这个问题上完全没有用,找到关于这个的文档比找到亨利八世第三任妻子的娘家姓更难。

我做错了什么,我该如何让它发挥作用?我走在正确的轨道上吗?

最佳答案

Am I on the right track?

是的。您在事件接收器中拥有的东西 - 您缺少一些代码来向 COM 服务器注册接收器。

VBProjectsVBComponents 接口(interface)实现(在非常深的地方)IConnectionPointContainer 接口(interface) - 您需要使用它来收集 IConnectionPoint 实例。要取消注册接收器,您需要一个数据结构来记住注册步骤提供给您的 int cookie

这是一个粗略的示例 - 假设您有一个包含这些字段的 App 类:

private readonly IConnectionPoint _projectsEventsConnectionPoint;
private readonly int _projectsEventsCookie;

private readonly IDictionary<VBComponents, Tuple<IConnectionPoint, int>> _componentsEventsConnectionPoints =
new Dictionary<VBComponents, Tuple<IConnectionPoint, int>>();

在构造函数的某处,您将使用 IConnectionPoint.Advise 注册接收器,并注册您的自定义事件处理程序:

var sink = new VBProjectsEventsSink();
var connectionPointContainer = (IConnectionPointContainer)_vbe.VBProjects;
Guid interfaceId = typeof (_dispVBProjectsEvents).GUID;
connectionPointContainer.FindConnectionPoint(ref interfaceId, out _projectsEventsConnectionPoint);

sink.ProjectAdded += sink_ProjectAdded;
sink.ProjectRemoved += sink_ProjectRemoved;
sink.ProjectActivated += sink_ProjectActivated;
sink.ProjectRenamed += sink_ProjectRenamed;

_projectsEventsConnectionPoint.Advise(sink, out _projectsEventsCookie);

然后,当添加一个项目时,您将使用 IConnectionPoint.Advise 为每个组件注册一个接收器,然后您可以注册您的自定义事件处理程序,并向您的字典添加一个条目:

void sink_ProjectAdded(object sender, DispatcherEventArgs<VBProject> e)
{
var connectionPointContainer = (IConnectionPointContainer)e.Item.VBComponents;
Guid interfaceId = typeof(_dispVBComponentsEvents).GUID;

IConnectionPoint connectionPoint;
connectionPointContainer.FindConnectionPoint(ref interfaceId, out connectionPoint);

var sink = new VBComponentsEventsSink();
sink.ComponentActivated += sink_ComponentActivated;
sink.ComponentAdded += sink_ComponentAdded;
sink.ComponentReloaded += sink_ComponentReloaded;
sink.ComponentRemoved += sink_ComponentRemoved;
sink.ComponentRenamed += sink_ComponentRenamed;
sink.ComponentSelected += sink_ComponentSelected;

int cookie;
connectionPoint.Advise(sink, out cookie);

_componentsEventsConnectionPoints.Add(e.Item.VBComponents, Tuple.Create(connectionPoint, cookie));
}

当一个项目被删除时,您使用IConnectionPoint.Unadvise 取消注册接收器,并删除字典条目:

void sink_ProjectRemoved(object sender, DispatcherEventArgs<VBProject> e)
{
Tuple<IConnectionPoint, int> value;
if (_componentsEventsConnectionPoints.TryGetValue(e.Item.VBComponents, out value))
{
value.Item1.Unadvise(value.Item2);
_componentsEventsConnectionPoints.Remove(e.Item.VBComponents);
}
}

然后您可以在您的处理程序中运行任何您想要的代码:

void sink_ComponentAdded(object sender, DispatcherEventArgs<VBComponent> e)
{
_parser.State.OnParseRequested(e.Item);
}

如果您的 App 类中有一个 Dispose 方法,那将是清理任何残留物的好地方:

public void Dispose()
{
_projectsEventsConnectionPoint.Unadvise(_projectsEventsCookie);
foreach (var item in _componentsEventsConnectionPoints)
{
item.Value.Item1.Unadvise(item.Value.Item2);
}
}

关于c# - 如何连接 COM 事件调度程序?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35593156/

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