订阅DTE事件似乎不起作用 - 事件不会被调用

时间:2010-10-06 15:13:15

标签: visual-studio visual-studio-2010 vsx

我在包中做了一个扩展,我调用了以下代码(当用户按下工具栏中的按钮时发生):

DocumentEvents documentEvents = (DTE2)GetService(typeof(DTE));
_dte.Events.DebuggerEvents.OnEnterBreakMode += DebuggerEvents_OnEnterBreakMode;
_dte.Events.DebuggerEvents.OnEnterDesignMode += DebuggerEvents_OnEnterDesignMode;
_dte.Events.DebuggerEvents.OnContextChanged += DebuggerEvents_OnContextChanged;
_dte.Events.DocumentEvents.DocumentSaved += new _dispDocumentEvents_DocumentSavedEventHandler(DocumentEvents_DocumentSaved);
_dte.Events.DocumentEvents.DocumentOpened += new _dispDocumentEvents_DocumentOpenedEventHandler(DocumentEvents_DocumentOpened);
void DocumentEvents_DocumentOpened(Document Document)
{
}

void DocumentEvents_DocumentSaved(Document Document)
{
}

void DebuggerEvents_OnEnterBreakMode(dbgEventReason Reason, ref dbgExecutionAction ExecutionAction)
{
}

void DebuggerEvents_OnContextChanged(Process NewProcess, Program NewProgram, Thread NewThread, StackFrame NewStackFrame)
{
}

private void DebuggerEvents_OnEnterDesignMode(dbgEventReason reason)
{
}

第一个和主要问题是订阅该事件不起作用。我试过了:

  • 打开新文件
  • 从调试中分离(因此可能会触发OnEnterDesignMode
  • 保存文档

这些似乎都没有任何效果,并且从未调用回调函数。

第二个问题是对事件行的订阅是USUALLY(订阅本身,回调不能如上所述),但是在运行订阅行后一段时间,例如:

_dte.Events.DebuggerEvents.OnEnterBreakMode -= DebuggerEvents_OnEnterBreakMode;

导致异常:

Exception occured!
System.Runtime.InteropServices.InvalidComObjectException: COM object that has been separated from its underlying RCW cannot be used.
   at System.StubHelpers.StubHelpers.StubRegisterRCW(Object pThis, IntPtr pThread)
   at System.Runtime.InteropServices.UCOMIConnectionPoint.Unadvise(Int32 dwCookie)
   at EnvDTE._dispDebuggerEvents_EventProvider.remove_OnEnterDesignMode(_dispDebuggerEvents_OnEnterDesignModeEventHandler A_1)

欢迎任何想法

谢谢! 维塔利彼得

2 个答案:

答案 0 :(得分:14)

发布我从MSDN论坛获得的answer,由Ryan Molden提供,以防万一:

  

我相信这里的问题是怎么回事   CLR处理COM端点(事件   汇)。如果我没记错的话   你打了   _applicationObject.Events.DebuggerEvents   CLR将成为你'链'的一部分   为。创建一个新的DebuggerEvents对象   属性访问并且不会缓存   它,那么它回到你身边,你   为它注册一个事件处理程序(其中   在...之间产生强烈的反对   TEMPORARY对象和你的对象到期   给代表,但不是来自你的代表   对象到临时对象,哪个   会阻止GC)。那你没有   将该对象存储在任何地方   立即GC符合条件且将会   最终是GC'ed。

我更改了代码以将DebuggerEvents存储为字段,这一切都开始正常工作。

答案 1 :(得分:8)

以下@VitalyB表示使用代码:

// list where we will place events.
// make sure that this variable is on global scope so that GC does not delete the evvents
List<object> events = new List<object>();

public void AddEvents(EnvDTE dte)
{
    // create an event when a document is open
    var docEvent = dte.Events.DocumentEvents;

    // add event to list so that GC does not remove it
    events.Add(docEvent );

    docEvent.DocumentOpened += (document)=>{

        Console.Write("document was opened!");
    };

    // you may add more events:
    var commandEvent = dte.Events.CommandEvents;
    events.Add(commandEvent );

    commandEvent.AfterExecute+=  etc...

}