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

Vit*_*lyB 12 vsx visual-studio-2010 visual-studio

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

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)
{
}
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

_dte.Events.DebuggerEvents.OnEnterBreakMode -= DebuggerEvents_OnEnterBreakMode;
Run Code Online (Sandbox Code Playgroud)

导致异常:

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)
Run Code Online (Sandbox Code Playgroud)

任何想法都将受到欢迎

谢谢!维塔利

Vit*_*lyB 14

发布我从MSDN论坛获得的答案,由Ryan Molden提供,以防它帮助任何人:

我相信这里的问题是CLR如何处理COM端点(事件接收器).如果我在你的'链'的_applicationObject.Events.DebuggerEvents部分中正确回想起来,CLR将为属性访问创建一个新的DebuggerEvents对象,并且不会对它进行缓存,因此它会返回给你,你注册一个事件它的处理程序(由于委托,它在TEMPORARY对象和对象之间创建一个强引用,但不是从您的对象到临时对象,这将阻止GC).然后你不会将该对象存储在任何地方,因此它立即符合GC条件,最终将被GC.

我更改了代码以将DebuggerEvents存储为字段,并且它们都开始正常工作.


Ton*_*Nam 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...

}
Run Code Online (Sandbox Code Playgroud)