Getting Up and Running on VSIP

One of the very cool tools we are working on here at the office is an ASP.NET based defect tracking system (we actually use it in house already and it is really helping us manage defects effectively as we push to get our CMS out the door). We have some very cool things going on with the system (like integration with NUnit to automatically keep bugs in sync if you use TDD). From the start, I've always thought it would be nice to have bugs show up in the IDE just like compiler errors. After all, runtime errors (like unhandled exceptions) are just as bad to have strewn around your code as compile time errors and a little visual notification would be nice. So, when I heard the VSIP extras were finally here, I rushed out and downloaded a copy. I quickly filled out the sign-up form and 30 seconds later I was downloading the install.

The first thing I should mention is that VSIP is not for the faint of heart. There is a reason there is no VB integration in the SDK ;-). The extras are definately cooler than writing everything in C#, but it is still very COM oriented. Most of the functionality is provided through lightweight COM wrappers and the documentation is sparse compared to the docs you are used to Microsoft providing. All the hard core samples are the still C++ code from the original SDK, but they do come in handy none-the-less when you just can't find what you are looking for in the docs.

Anyway, back to getting up and running... I stepped through the new VSIP wizard to create my basic VS addin and had the skeleton up and running in no time. Unfortunately, VS crashed and I had to restart shortly thereafter, but since the projects were already on disk, it wasn't too hard getting them back online. Perhaps it was this crash, or perhaps the docs are wrong, but when I tried to launch the Visual Studio Exp to test the stuff, the debugging info wasn't set. If this happens to you, just go to project properties and enter the Visual Studio Exp information in the debugging section (you can find this by selecting properties of the start menu item that the SDK installer should have added).

Well... the first shot at debugging failed. The icon showed up on the “Other windows“ menu, but no dice when I clicked it to show the window. I started digging around, and then I remembered that the fact that VS.NET has the icon doesn't mean jack as far as the DLL is concerned, because all that stuff is stored in the registry to get better start times when you launch VS.NET for the first time. So, it dawned on me that I should check the project properies and make sure that my project was registered for COM interop because the class might not even be loading. As it turns out, this assumption was correct. After setting the register for COM interop option in the project settings, everything was a go and my window had no problems displaying itself.

So, now you have a basic tool window with a button on it. What happens when you want to do something cool (by cool I mean something other than display a freaking user control). Well, MS doesn't make this too easy, but it is possible with a little digging. In my case, the first task was getting custom underlines to show up on the screen. A few weeks ago, I had spent a few hours poking around the C++ SDK, so I remembered that I had narrowed the location of underlining stuff down to somewhere the TextBuffer related classes. The problem I faced is, how the hell do you get one of these text buffer objects?

To access just about any functionality in VS.NET, you need to query for services that have been “proffered.” The base interface for most UI related stuff is IVsUIShell. From here, you can query for the open document windows like so:

shell.GetDocumentWindowEnum(out frames);

This returns a IEnumWindowFrames interface that you can use to enumerate the open windows. However, this interface fills an array of IVsWindowFrame interfaces, and IVsWindowFrame doesn't contain any properties that suggest they would return a CodeWindow, or anything even remotely useful to us (nor can it be casted as a text buffer or code window). A little digging through the SlnExt sample and I found the solution. Use the GetProperty method and pass in the value for the document window (-3001) and you will get an object that you can cast as an IVsWindowPane or IVsCodeWindow. From there, the code to underline something is fairly straightforward if you are willing to dig through some docs and think a little:

Microsoft.VisualStudio.TextManager.Interop.IVsCodeWindow window = pane as Microsoft.VisualStudio.TextManager.Interop.IVsCodeWindow;

if(window != null)
{

Microsoft.VisualStudio.TextManager.Interop.IVsTextLines lines;
window.GetBuffer(
out
lines);
lines.CreateLineMarker((int)Microsoft.VisualStudio.TextManager.Interop.MARKERTYPE.MARKER_OTHER_ERROR, 0, 0, 1,0, null, null
);
lines.FindMarkerByLineIndex((
int)Microsoft.VisualStudio.TextManager.Interop.MARKERTYPE.MARKER_OTHER_ERROR, 0, 0, 0, out marker);

}

So, there you have it. Now you can get the code window and do all sorts of interesting things (like build refactoring tools before Whidbey gets here).

No Comments