Visio VSTO插件中使用AddAdvise添加事件接收器失败问题排查
解决Visio VSTO插件中AddAdvise触发COM异常的问题
核心问题分析
你遇到的0x86DB0898 COM异常,主要由两个原因导致:
- 事件接收器实例被.NET垃圾回收器提前回收,导致Visio COM对象无法找到对应的回调对象
- 事件源选择与事件代码的作用范围不匹配
解决方案步骤
1. 将事件接收器实例存储为类级成员
局部变量声明的ShapeDeleteEventSinkInstance会在代码块执行完毕后被标记为可回收,而Visio需要持续持有该对象的引用。需将其改为插件类的成员变量:
' 在ThisAddIn类中声明类级成员 Private shapeDeleteSink As ShapeDeleteEventSink ' 初始化事件处理的方法 Public Sub AttachShapeDeleteEvent() If Globals.ThisAddIn.Application.ActiveDocument Is Nothing Then Return ' 实例化接收器并保存引用 shapeDeleteSink = New ShapeDeleteEventSink ' 文档级事件使用Document.EventList,应用级事件使用Application.EventList Dim eventList As Visio.EventList = Globals.ThisAddIn.Application.ActiveDocument.EventList Dim shapeDeleteEvent As Visio.Event = eventList.AddAdvise( _ CShort(Visio.VisEventCodes.visEvtCodeShapeDelete), _ shapeDeleteSink, _ "", _ "Shape deleted event" _ ) End Sub
2. 显式标记事件接收器类为ComVisible
显式标记可避免潜在的互操作兼容性问题:
Option Strict On Imports System.Diagnostics Imports Microsoft.Office.Interop Imports Visio = Microsoft.Office.Interop.Visio <ComVisible(True)> Public Class ShapeDeleteEventSink Implements Visio.IVisEventProc Public Function VisEventProc(nEventCode As Short, pSourceObj As Object, nEventID As Integer, nEventSeqNum As Integer, pSubjectObj As Object, vMoreInfo As Object) As Object Implements Visio.IVisEventProc.VisEventProc Debug.Print("A shape was deleted event fired") Return Nothing End Function End Class
3. 确认事件代码与事件源的匹配性
visEvtCodeShapeDelete属于文档级事件,使用ActiveDocument.EventList是正确的;如果是全局快捷键事件(如visEvtCodeKeyDown),则需要切换为Application.EventList作为事件源- 你的参数类型实现与Interop定义完全匹配(
nEventCode为Short,nEventID和nEventSeqNum为Integer),无需修改
键盘事件扩展说明
对于visEvtCodeKeyDown这类键盘事件,可通过pSubjectObj直接获取Visio.KeyboardEvent对象,从而获取按键详情:
Public Function VisEventProc(nEventCode As Short, pSourceObj As Object, nEventID As Integer, nEventSeqNum As Integer, pSubjectObj As Object, vMoreInfo As Object) As Object Implements Visio.IVisEventProc.VisEventProc If nEventCode = CShort(Visio.VisEventCodes.visEvtCodeKeyDown) Then Dim kbEvent As Visio.KeyboardEvent = DirectCast(pSubjectObj, Visio.KeyboardEvent) Debug.Print($"Pressed key: {kbEvent.KeyCode}, Modifiers: {kbEvent.KeyButtonState}") End If Return Nothing End Function
内容的提问来源于stack exchange,提问作者DotNET Afficionado
相关产品推荐
相关产品推荐

