如何连接COM事件分发器?VBIDEAPI公开了非常神秘的_dispVBComponentsEvents接口(以及其他接口),我可以使用它来捕捉VBE中各种有趣的事件。因此,我在一个旨在捕获事件并为我的应用程序的其余部分引发“正常”.net事件的类中实现了该接口,如下所示:publicclassVBComponentsEventDispatcher:_dispVBComponentsEvents{publicvoidItemAdded(VBComponentVBComponent){OnDispatch(ComponentAdded,VBComponent);}公共事件EventHandlerComponentRemoved;publicvoidItemRemoved(VBComponentVBComponent){OnDispatch(ComponentRemoved,VBComponent);}公共事件EventHandlerComponentRenamed;publicvoidItemRenamed(VBComponentVBComponent,stringOldName){varhandler=ComponentRenamed;if(handler!=null){handler.Invoke(this,newDispatcherRenamedEventArgs(VBComponent,OldName));}}publiceventEventHandlerComp;onentSelected(VBComponentVBComponent){OnDispatch(ComponentSelected,VBComponent);}公共事件EventHandlerComponentActivated;publicvoidItemActivated(VBComponentVBComponent){OnDispatch(ComponentActivated,VBComponent);}公共事件EventHandlerComponentReloaded;publicvoidItemReloaded(VBComponentVBComponent){OnDispatch(ComponentReloaded,VBComponent);}privatevoidOnDispatch(EventHandlerdispatched,VBComponentcomponent){varhandler=dispatched;if(handler!=null){handler.Invoke(this,newDispatcherEventArgs(component));我希望像这样使用这个类:varcomponentsEvents=newVBComponentsEventDispatcher();componentsEvents.ComponentAdded+=componentsEvents_ComponentAdded;componentsEvents.ComponentActivated+=componentsEvents_ComponentActivated;//...voidcomponentsEvents_ComponentAdded(objectsender,DispatcherEventArgse){Debug.WriteLine(string.Format("Component'{0}'wasadded.",e.Item.Name));}voidcomponentsEvents_ComponentActivated(objectsender,DispatcherEventArgse){Debug.WriteLine(string.Format("组件'{0}'被激活。",e.Item.Name));但它不起作用,我没有得到调试输出并且断点没有被击中显然我不知道我在做什么。MSDN在这个问题上完全没有用,查找这方面的文档比查找亨利八世第三任妻子的娘家姓更难。我做错了什么,我怎样才能让它发挥作用?我在正确的轨道上吗?System.Runtime.InteropServices命名空间公开了一个静态ComEventsHelper类,用于将托管委托连接到非托管调度源。这基本上与其他答案完全相同,但连接点是在运行时可调用包装器中处理的,而不是必须从调用代码中显式管理(从而使其更健壮)。我怀疑这就是PIA在内部处理源接口的方式(反编译有问题的Microsoft.Vbe.Interop已经够糟糕了,很难说)。在这种情况下,由于某些无法解释的原因,有问题的接口没有声明为源接口,因此PIA构建没有在运行时包装器中连接事件处理程序。所以...您可以手动连接包装器类中的处理程序并将它们作为包装事件转发,但仍然必须处理与RCW的连接点的繁重工作(和线程安全管理)。请注意,您需要来自引用类型库的2条信息:_dispVBComponentsEvents接口的guid和您有兴趣侦听的非托管事件的DispId:privatestaticreadonlyGuidVBComponentsEventsGuid=newGuid("0002E116-0000-0000-C000-000000000046");privateenumComponentEventDispId{ItemAdded=1,ItemRemoved=2,ItemRenamed=3,ItemSelected=4,ItemActivated=5,ItemReloaded=6}然后,将它们连接到类包装器的构造器(为简洁起见只显示一个)...privatedelegatevoidItemAddedDelegate(VB.VBComponentvbComponent);私有只读ItemAddedDelegate_componentAdded;publicVBComponents(VB.VBComponentstarget){_target=target;_componentAdded=OnComponentAdded;ComEventsHelper.Combine(_target,VBComponentsEventsGuid,(int)ComponentEventDispId.ItemAdded,_componentAdded);}...并转发事件:publiceventEventHandler>ComponentAdded;privatevoidOnComponentAdded(VB.VBComponentvbComponent){OnDispatch(ComponentAdded,VBComponent);}privatevoidOnDispatch(EventHandler>dispatched,VB.VBComponentcomponent)={varhanddi派遣;if(handler!=null){handler.Invoke(this,newDispatcherEventArgs(newVBComponent(component)));完成后,通过调用ComEventsHelper.Remove注销委托:ComEventsHelper.Remove(_target,VBComponentsEventsGuid,(int)ComponentEventDispId.ItemAdded,_componentAdded);上面的示例根据问题使用了包装器类,但是如果您需要在处理COM事件或将其传递给其他侦听器之前将附加功能附加到COM事件,您可以从任何地方使用它相同的方法我走对了吗?是的。你在事件接收器中有什么——你缺少一些代码来向COM服务器注册接收器。VBProjects和VBComponents接口实现(某处非常深)IConnectionPointContainer接口-您需要使用它来收集IConnectionPoint实例。要取消注册接收器,您需要一个数据结构来记住注册步骤给您的intcookie。这是一个粗略的示例-假设您有一个包含以下字段的App类:privatereadonlyIConnectionPoint_projectsEventsConnectionPoint;私有只读int_projectsEventsCookie;privatereadonlyIDictionary>_componentsEventsConnectionPoints=newDictionary>();在构造函数的某处,您将使用IConnectionPoint.Advise注册接收器,并注册您的自定义事件处理程序:varsink=newVBProjectsEventsSink();varconnectionPointContainer=(IConnectionPointContainer)_vbe.VBProjects;GuidinterfaceId=typeof(_dispVBProjectsEvents).GUID;connectionPointContainer.FindConnectionPoint(refinterfaceId,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为每个组件注册一个接收器,然后您可以注册自定义事件处理程序,并向您的字典添加一个条目:voidsink_ProjectAdded(objectsender,DispatcherEventArgse){varconnectionPointContainer=(IConnectionPointContainer)e.Item.VBComponents;GuidinterfaceId=typeof(_dispVBComponentsEvents).GUID;IConnectionPoint连接点;connectionPointContainer.FindConnectionPoint(refinterfaceId,outconnectionPoint);varsink=newVBComponentsEventsSink();sink.ComponentActivated+=sink_ComponentActivated;sink.ComponentAdded+=sink_ComponentAdded;sink.ComponentReloaded+=sink_ComponentReloaded;sink.ComponentRemoved+=sink_ComponentRemoved;sink.ComponentRenamed+=sink_ComponentRenamed;sink.ComponentSelected+=sink_ComponentSelected;内部cookie;connectionPoint.Advise(sink,outcookie);_componentsEventsConnectionPoints.Add(e.Item.VBComponents,Tuple.Create(connectionPoint,cookie));}删除项目后,使用IConnectionPoint.Unadvise取消注册表接口,并删除字符串示例:voidsink_ProjectRemoved(objectsender,DispatcherEventArgse){Tuplevalue;if(_componentsEventsConnectionPoints.TryGetValue(e.Item.VBComponents,outvalue)){值e.Item1.Unadvise(value.Item2);_componentsEventsConnectionPoints.Remove(e.Item.VBComponents);然后,您可以在处理程序中运行任何您想要的代码:如果您的App类中有Dispose方法,那么这将是清理任何残留物的好地方:以上是C#学习教程:如何连接COM事件调度程序?如果分享的内容对你有用,需要进一步了解C#学习教程,希望你多多关注——publicvoidDispose(){_projectsEventsConnectionPoint.Unadvise(_projectsEventsCookie);foreach(varitemin_componentsEventsConnectionPoints){item.Value.Item1.Unadvise(item.Value.Item2);}}本文收集自网络,不代表立场。如涉及侵权,请点击右侧联系管理员删除。如需转载请注明出处: