Кажется, подписка на события DTE не работает - События не вызывают - PullRequest
12 голосов
/ 06 октября 2010

Я сделал расширение внутри пакета, и я вызываю следующий код (происходит, когда пользователь нажимает кнопку на панели инструментов):

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
  • Сохранение документа

Неткажется, что они имеют какой-либо эффект, и функции обратного вызова никогда не вызывались.

Вторая проблема заключается в том, что подписка на строку события работает ОБЫЧНО (сама подписка, обратный вызов не работает, как описано выше), ночерез некоторое время запуска строки подписки, например:

_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 ]

14 голосов
/ 10 октября 2010

Отправка ответа , который я получил от форумов MSDN Райана Молдена, на случай, если он кому-нибудь поможет:

Я считаю, что проблема здесь в том, как CLR обрабатывает конечные точки COM (событие раковины). Если я правильно помню, когда ты ударил _applicationObject.Events.DebuggerEvents часть вашей «цепи», CLR будет создать новый объект DebuggerEvents для доступ к собственности и не кэшировать это, поэтому он возвращается к вам, вы зарегистрировать обработчик событий для него (который создает сильный реф между ВРЕМЕННЫЙ объект и ваш объект из-за делегату, но НЕ от вашего объект на временный объект, который помешал бы GC). Тогда ты не хранить этот объект в любом месте, так что это немедленно GC имеет право и будет в конечном итоге быть GC'ed.

Я изменил код для хранения DebuggerEvents в качестве поля, и все стало работать нормально.

8 голосов
/ 21 августа 2012

Вот что означает @ 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...

}
...