12

I used the "Add-In for Visual Studio" wizard to create a new Addin project and now, I'm trying to add some event handlers:

public void OnConnection(object application, ext_ConnectMode connectMode, object addInInst, ref Array custom)
{
    _applicationObject = (DTE2)application;
    _addInInstance = (AddIn)addInInst;

    _applicationObject.Events.BuildEvents.OnBuildBegin += BuildEvents_OnBuildBegin;
    _applicationObject.Events.BuildEvents.OnBuildDone += BuildEvents_OnBuildDone;
    _applicationObject.Events.SelectionEvents.OnChange += SelectionEvents_OnChange;
    _applicationObject.Events.DocumentEvents.DocumentOpened += DocumentEvents_DocumentOpened;
    _applicationObject.Events.DocumentEvents.DocumentSaved += DocumentEvents_DocumentSaved;
}

But whatever I do, my handlers are never executed!

Am I blind? Do I have to do anything else to register these handlers or why doesn't it work?

spajce
  • 7,044
  • 5
  • 29
  • 44
main--
  • 3,873
  • 1
  • 16
  • 37

2 Answers2

22

Seems you're a victim of the Garbage Collector. See: http://www.mztools.com/articles/2005/mz2005012.aspx

 private readonly BuildEvents _buildEvents;
 private readonly SelectionEvents _selectionEvents;
 private readonly DocumentEvents _documentEvents;
 private readonly Events _events;

 public void OnConnection(object application, ext_ConnectMode connectMode, object addInInst, ref Array custom)
 {
     _applicationObject = (DTE2)application;
     _addInInstance = (AddIn)addInInst;
     _events = _applicationObject.Events;

     _buildEvents = _events.BuildEvents;
     _buildEvents.OnBuildBegin += BuildEvents_OnBuildBegin;
     _buildEvents.OnBuildDone += BuildEvents_OnBuildDone;

     _selectionEvents = _events.SelectionEvents;
     _selectionEvents.OnChange += SelectionEvents_OnChange;

     _documentEvents = _events.DocumentEvents;
     _documentEvents.DocumentOpened += DocumentEvents_DocumentOpened;
     _documentEvents.DocumentSaved += DocumentEvents_DocumentSaved;
 }
jessehouwing
  • 106,458
  • 22
  • 256
  • 341
  • 1
    This doesn't appear to be the case. By default, the add-in wizard will make it so that the shown `_applicationObject` is created at the class level, not as a local variable – Earlz Jan 13 '13 at 18:16
  • Not just the _applicationObject, but you need to strore the BuildEvents, SelectionEvents and DocumentEvents at class level too. – jessehouwing Jan 13 '13 at 18:57
  • @jessehouwing I tested this with the DocumentEvents. Didn't help. – main-- Jan 13 '13 at 19:25
  • 1
    Do you also store the Events item? – jessehouwing Jan 13 '13 at 20:55
  • @main-- this fixed my problem. Did you do something like `selectionevents=_applicationObject.Events.SelectionEvents;` (with `selectionevents` declared at the class level), and then do `selectionevents.OnChange+= ....`? – Earlz Jan 13 '13 at 22:36
  • 2
    @Earlz Oh, right, I registered my event handlers to Events.DocumentEvents instead of my field. I won't be able to test this before wednesday, so if you say that this fixes the problem, I'll mark the answer as accepted right now. – main-- Jan 14 '13 at 06:07
  • 1
    Can only say I've had the same experience a while ago while creating a Outlook Addin. The Common Object Model(COM) is very confusing to work with at first. There are other gotchas with COM, so I suggest @main-- to read a few tutorials first. – Destrictor Jan 14 '13 at 11:22
  • I'll reward this for the bounty when you confirm that this fixes it @main-- – Earlz Jan 14 '13 at 15:57
  • @main--: Was going to answer this. You need to keep references, otherwise you will be collected and the events will never fire. –  Jan 14 '13 at 17:09
  • 1
    I've been so frustrated by this. This answer is over 9000. – sircodesalot Jun 28 '13 at 21:05
1

If you look at applicationObject in the debugger you'll see its a COM object, but the xxxEvents classes are not (If you can't get the code to break on OnConnection, then possibly your addin isn't getting loaded when you debug, check the tools menu)

Events in COM are handled by a separate COM interface (several in this case) in the other direction which the server (VS) calls to fire them.

Although COM objects have a similar typed assembly concept to CLR assemblies they are unmanaged code internally, so cannot hold roots to managed objects.

So although you can hook a delegate to a COM event in a way that looks exactly like a native CLR event, your event is hooked to an RCW (runtime callable wrapper). There is a COM reference from the server to the RCW com interface, but without a CLR root the RCW eventually gets disposed which unloads the com interface, after which you won't sink any events.

I'm not sure but I think this normally works when you consume a single COM object with a direct association to its event interfaces so its maybe due to how the DTE COM interface is structured...

Anyway as others have said you just need any kind of managed reference to the BuildEvents, SelectionEvents and DocumentEvents classes from the app object to fix it. Multiple instances of VS load separate instances of the add in so you could just add a list of static object refs and set them in OnConnect.

Subscription to DTE events doesn't seem to work - Events don't get called

http://msdn.microsoft.com/en-us/library/k639e386.aspx

Community
  • 1
  • 1
Peter Wishart
  • 11,600
  • 1
  • 26
  • 45