Wednesday, April 09, 2008

Debugging Visual Studio packages (stories from the crypt)

If you ever developed Visual Studio integration package, you should be familiar with load failure problem. The problem manifests itself when properly deployed package cannot be loaded with error message displayed.

I'd like to stress the deployed part of the above; when such problem occurs in the development environment, there are number of typical issues causing this such as invalid registry (missing CodeBase attribute etc.), invalid PLK key or missing dependencies (am assuming here that package with invalid PLK does not get distributed :). To diagnose such issues one can use Package Load Analyzer, distributed as part of Visual Studio SDK.

However, when the issue occurs at some other workstation where properly tested package is deployed, this option is not too useful (you cannot ask every user to install VS SDK, can you?). And believe it or not, these things happen even to the software that is rock solid in local test environment. So here is my take on figuring out why deployed package does not work:

  1. Ask the user to export registry branch with package registration information
  2. Ask the user to run Visual Studio with logging enabled (devenv /log [log file path]) and ship you the log; the log will tell you if you have PLK or similar problems – in a sense it is performing the same function as Package Load Analyzer only without fancy interface
  3. And finally, do tracing in your code! By "tracing" I mean trace every single dubious statement in package Initialize method (and every exception elsewhere however unlikely it might seem). Though better approach would be to utilize Visual Studio Output pane, sometimes the overhead is too big for unlikely scenarios. But however unlikely, if you put Trace statement in that location it can be crucial in diagnosing the problem. Mind, I advocate tracing over message boxes and other UI elements only for the problems that are deemed unlikely (that is never occur in testing, for example).
    Then if you have copious tracing embedded in your code, you can instruct the user to place diagnostics section as into devenv.exe.config file (located in IDE folder together with devenv.exe) and thus get the snapshot of what is going on in your package

This sequence can be pretty helpful in diagnosing problems in packages that otherwise are functioning properly in most environments. If you have alternative approaches, it would be interesting to learn them – leave a comment on the blog!

Wednesday, February 13, 2008

Team Foundation Server and VSIP tidbits

One basic question that immediately comes up when writing Visual Studio Integration Package (VSIP) that needs to make use Team Foundation Server extensiblity, is how to handle TFS extensibility objects. "How to" for writing add-ins is well described in now classic blog post by Ed Hintz; while most of it applies also to VSIP there are some missing pieces that I will try to address.

As a first step, one needs to get TFS extensibility objects; once the extensibility objects are available, there is no major difference between add-in (as described in Ed's article) development and VS package.

To obtain reference to TFS specific objects (such as VersionControlExt) one needs DTE2 instance; in VSIP one may use the following approach to retrieve global DTE:

// use package GetService method to get
// extensibility service
EnvDTE.IVsExtensibility extensibility = 
   GetService(typeof(EnvDTE.IVsExtensibility)) as EnvDTE.IVsExtensibility;
// get IDE Globals object and DTE from that
EnvDTE80.DTE2 dte2 = 
   extensibility.GetGlobalsObject(null).DTE as EnvDTE80.DTE2;
            Debug.Assert(dte2 != null, "No DTE2");

Once reference to DTE2 is available, reference to TFS extensibility objects may be obtained as follows:

VersionControlExt versionControlExt = 
   dte2.GetObject("Microsoft.VisualStudio.TeamFoundation.VersionControl.VersionControlExt") 
   as VersionControlExt;

Another frequently asked question is how to monitor when TFS server connection status in Visual Studio IDE. There is no special event exposed for this purpose; however, ProjectContextChanged event of TeamFoundationServerExt object may be used for this purpose (see Tim Noonan's excellent post for more details on this event). When TFS server is disconnected, active project context properties become null; when connected, the values in the context can be used to get reference to TeamFoundationServer object:

private void ProjectContextChanged(object sender, EventArgs e)
{
    // server is disconnected
    if (_teamServerExt.ActiveProjectContext.DomainName == null)
        ; // do disconnected stuff
    else 
    {
        // connected, can get reference to server
        //TeamFoundationServerFactory.GetServer(
        //    _teamServerExt.ActiveProjectContext.DomainUri.ToString());                
    }
}

Tracking TFS server connection status may seem unimportant, but it becomes vital in scenarios with several TFS servers available, or where VS may be started disconnected with connection to TFS established later on. In such cases assuming that the connection is always active may lead to some ugly bugs in your package.

Sunday, November 04, 2007

How to extend TFS-related menus in VS

I wrote a while ago about extending TFS-related menus, and as a follow up just wanted to elaborate a bit.

Usually, the problem with adding menus related to TFS is that the parent menu GUIDs/command IDs are not well known. For example, the following post describes typical problem.

But once the GUID:id pair is known, adding the menus is a no brainer. The easiest approach I have found so far is to use EnableVSIPLogging registry setting. That simple setting may save countless hours full of frustration (and I am speaking from experience :).

And those IDs is not something that will change within same version of VS (though for 2008 probably some testing will be required).