Saving DTE and other COM Event Hook-ups

To avoid losing an event hook-up from a COM source it is necessary to hold a local reference to the source of the event to avoid unwanted garbage collection.  This is a concern for VSTA hosts hooking into DTE events as well as VSTA add-ins which use a direct reference to a COM host instead of a proxy.


For example, in the SDK the DTE source events are each saved in a local variable and hooked into from these variables.  If you attempt to hook into the events without saving event sources the hook-ups can be lost.


To test if an event hookup will preset, call GC.Collect in the event sink and re-fire.  If the event is hit again the hookup should persist.

Example of how to hook into DTE events from a host:
When events sources are saved, event hookups will continue to work after garbage collection.
private EnvDTE.BuildEvents buildEvents; 
private void HookupDteEvents_GOOD()
{
    // Save a copy of the event sync locations so they don't get
    // garbage collected.
    this.buildEvents = this.dte.Events.BuildEvents; 

    this.buildEvents.OnBuildBegin += new
        EnvDTE._dispBuildEvents_OnBuildBeginEventHandler(buildEvents_OnBuildBegin);

}

void buildEvents_OnBuildBegin(EnvDTE.vsBuildScope Scope, 
     EnvDTE.vsBuildAction Action)

 {

     //Call GC.Collect to test if the event hookup will persist

     System.Windows.Forms.MessageBox.Show(

         "Call GC.Collect after firing event to test hook-up");

     GC.Collect();

 } 

Example of how NOT to hook into DTE events from a host:
When events sources are not saved, event hookups will not continue to work after garbage collection.
private void HookupDteEvents_BAD()
{
    // DON’T DO THIS
    // Hook into the event through the dte w/o saving source
    this.dte.Events.BuildEvents.OnBuildBegin +=new
        EnvDTE._dispBuildEvents_OnBuildBeginEventHandler(buildEvents_OnBuildBegin);

}

void buildEvents_OnBuildBegin(EnvDTE.vsBuildScope Scope, 
     EnvDTE.vsBuildAction Action)
 {

     //Call GC.Collect to test if the event hookup will persist

     System.Windows.Forms.MessageBox.Show(

         "Call GC.Collect after firing event to test hook-up");

     GC.Collect();

 }


Example of how to hook into host events from an add-in using a direct reference to a COM host:
When events sources are saved, event hookups will continue to work after garbage collection.  From MyAppVB6 sample.
private void AppAddIn_Startup(object sender, EventArgs e)
{
    this.Document.KeyPress += new 
            __Document_KeyPressEventHandler(Document_KeyPress); 

    doc = this.Document;

    doc.KeyPress += new 
            __Document_KeyPressEventHandler(doc_KeyPress);

    //if the local variable is saved, hooking into this.Document will work
    //this.Document.KeyPress += new 
    //      __Document_KeyPressEventHandler(Document_KeyPress);

}

Document doc;
void doc_KeyPress(ref short KeyCode)
{

    System.Windows.Forms.MessageBox.Show(
            "Hooking into this.Document with saving it won't work");   

    GC.Collect();           
}         

Example of how NOT to hook into host events from an add-in using a direct reference to a COM host:
When events sources are not saved, event hookups will not continue to work after garbage collection. From MyAppVB6 sample.
private void AppAddIn_Startup(object sender, EventArgs e)
{
    this.Document.KeyPress += new 
            __Document_KeyPressEventHandler(Document_KeyPress); 
}

void Document_KeyPress(ref short KeyCode)
{

    System.Windows.Forms.MessageBox.Show(
            "Hooking into this.Document w/o saving it won't work"); 

    GC.Collect();
}

 

 


Posted Apr 29 2009, 11:00 AM by Melody
Filed under: , , , , , ,
Copyright Summit Software Company, 2008. All rights reserved.