Monday, November 26, 2007

Moving Day for VSTO

I have been working on a Microsoft Office Business application sporadically with the Beta 2 version of Visual Studio.NET 2008. Once I got my hands on the RTM version of 2008, I tried to bring the project across. It did not immediately compile. I clocked in at about 20 build errors. A number of the assembly references were not recognized – apparently there was some renaming between Beta 2 and the real thing.I did a Google search on one of the unrecognized assembly references:

Microsoft.VisualStudio.Tools.Office

… and I was pointed towards the Visual Studio 2008 Readme file. But of course. That’s a handy place to put it, but I gave up reading readme files years ago – when they stopped being pithy descriptions of important issues and started becoming dumping grounds for any minutiae that the developer had in mind.

But this particular readme file had some good information. It began like this:

You may experience build and runtime errors when you build and run Beta 2 Office projects in the release version of Visual Studio 2008. Changes have been made to a number of VSTO reference assemblies.

Bingo. Then we got a nice little table:


Old Reference New Reference
Microsoft.VisualStudio.Tools.Applications.ServerDocument.dll Microsoft.VisualStudio.Tools.Applications.ServerDocument.v9.0.dll
Microsoft.VisualStudio.Tools.Office.dll Microsoft.Office.Tools.v9.0.dll
Microsoft.VisualStudio.Tools.Office.Common.dll Microsoft.Office.Tools.Common.v9.0.dll
Microsoft.VisualStudio.Tools.Office.Excel.dll Microsoft.Office.Tools.Excel.v9.0.dll
Microsoft.VisualStudio.Tools.Office.Outlook.dll Microsoft.Office.Tools.Outlook.v9.0.dll
Microsoft.VisualStudio.Tools.Office.Word.dll Microsoft.Office.Tools.Word.v9.0.dll


The main change seemed easy enough to follow: The Microsoft.VisualStudio.Tools.Office.* assemblies had become Microsoft.Office.Tools.*

I added the references noted above, and got it down to 9 compile errors. I then noticed that the table was not comprehensive. My suspicions fell on one of the last remaining missing assemblies --Microsoft.VisualStudio.Tools.Applications.AddInBase. I made the mistake of picking the namespace that looked the most like the old one to take up the slack -- Microsoft.VisualStudio.Tools.Applications.AddInManager. Wrong.

So I applied the formula that seems to be implied by the conversion table and looked for the following assembly: Microsoft.Office.Tools.Applications.AddInBase. Nope. Didn’t exist.

Back to Google:

Microsoft.VisualStudio.Tools.Applications.AddInBase

No hits. Wow. It’s not often your search term goes for 0-for-internet. Surely, the assembly name will be found somewhere within MSDN. Nope. I’m starting to wonder where that came from. Let’s try deleting it from the references. Boom. No effect on the number of errors.

All right, then. Put that one aside and see where the errors are coming from. I started to suspect this namespace:


Microsoft.VisualStudio.Tools.Applications.Runtime


…it seems to be giving the compiler heartburn. I look closer at one of the errors:

The type 'Microsoft.VisualStudio.Tools.Applications.Runtime.IEntryPoint' is defined in an assembly that is not referenced. You must add a reference to assembly 'Microsoft.VisualStudio.Tools.Applications.Runtime.v9.0, Version=9.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'.

Isn’t that interesting? It’s telling me what assembly is missing… and I didn’t seem to have that reference in the project before. Taking the tip that the compiler gave me, I added that assembly reference (Microsoft.VisualStudio.Tools.Applications.Runtime.v9.0) And now we’re down to one compiler error.

The final error concerns the Ribbon Add-In that I created for my beta project. This was what drew me to use VS.NET 2008 in the first place. It was the only environment where you could use the designer to create a ribbon add-in that was specific to one document. (You could get to the same end result in VS.NET 2005 + VSTO, but there was a whole lot of rolling your own.)

In this case, I used the designer to build the Add-In, so the code was generated. That’s always fun to debug, because it’s sprinkled with warnings about how you should not touch the code under any circumstances. But let’s see if we can hone in. First, the compiler takes exception to the parent class – WordRibbon. So. If the shipping version of VS.NET2008 doesn’t like the way Beta 2 generated code, the next step is to see how the shipping version does it.

For comparison’s sake, I create a new Office project – a Word document. I add a new item to the project: Visual C# Items -> Office -> Ribbon (Visual Designer) The parent class that it generates in this case is OfficeRibbon. Otherwise, the method calls look fairly similar. So I simply change the WordRibbon to OfficeRibbon… and this time, the project compiles. Hit debug… and it fails on a SQL permission error. Vista’s new security paradigm strikes again – I’ll blog about that another day. I clean up that error, and now the application runs in debug mode… except my Ribbon Add-in does not show up. It does not throw an error, but neither does it show up.

Back to the test project I created to see how VS.NET 2008 RTM creates the Ribbon Add-In. That one works just fine – it shows up on the Ribbon where it’s supposed to. I launch another instance of VS.NET 2008, so that I can have both projects open simultaneously. I hone in on the generated code, which mainly consists of InitializeComponent() method. Other than the specific buttons and so forth, the code looks awfully similar.But I find one class in the *.Designer.cs file that’s not in the beta version

    partial class ThisRibbonCollection : Microsoft.Office.Tools.Ribbon.RibbonReadOnlyCollection
{
internal TestRibbon TestRibbon
{
get { return this.GetRibbon<TestRibbon>(); }
}
}







So I add that block of code to my new project (changing the class names). Why not? But that has no effect whatsoever.





This is an opportunity to dig into the internals of how the Ribbon Add-Ins generate code… but, then again, it’s not like I’m ever going to go back to the beta version of VS.NET 2008. It’s probably easier to add a new item to my new project – recreate the Ribbon Add-In with VS.NET 2008 RTM’s designer. That gives me the straightest line between where I am and where I want to go.





Recreating the Ribbon Add-In is pretty straightforward, mainly consisting of dragging and dropping a number of buttons. All the functionality behind the buttons resides in other classes, so I just have to wire simple method calls to the buttons’ click events.





One mildly interesting thing did come out of the exercise. Whereas the previous iteration of Add-In allowed me to create a reference to my Word document when the class is initialized:







IMPWriteFactorFour.ThisDocument _wordDoc = Globals.ThisDocument;




… which I then referenced within the Add-In class to execute methods:







        private void nextLineButton_Click(object sender, RibbonControlEventArgs e)
{
_wordDoc.advanceLine();
}







This caused a null reference error in the RTM version. It did not recognize the _wordDoc variable as a reference to the current Word document. I had to change the methods to explicitly set that variable.







        private void nextLineButton_Click(object sender, RibbonControlEventArgs e)
{
_wordDoc = Globals.ThisDocument;
_wordDoc.advanceLine();
}




… and it was happy. Apparently, something about the order of loading Ribbon Add-Ins changed between Beta 2 and RTM.





And now I can proceed, from the point I left off on Beta 2.





Lessons Learned?





I found it interesting that I had to change a number of assembly references, but the actual namespaces within the code did not have to change. Once I added the correct assembly, the code compiled. In looking at the assembly naming, I'm guessing that the dev team wanted to standardize the naming in the final release to conform to the naming conventions in the previous versions of VSTO. It was also interesting to see the differences in functionality between the beta and final releases of the Ribbon Add-Ins.

1 comment:

Abhishek Katoch said...

This is a good article.saved a day for me...

Thanks