Sam Gentile's Radio Weblog : Partying with .NET

 

Click to see the XML version of this web page.

Click here to send an email to the editor of this weblog.

 
 

Mixing VSIP Unmanaged Code with Managed Code

Today, in the "real" world, I was working on a mechanism to allow us to write VS.NET Automation model code in C# and then call it, through .NET's COM Interop mechanism, from ATL/C++ COM unmanaged components which contain a VSIP code. Let me explain. I have been doing some work integrating an environment with Visual Studio .NET. There are really two major choices: use the automation model of VS.NET or pay $30,000 and join the Visual Studio Integration Program (http://msdn.microsoft.com/vstudio/vsip/default.asp) and get the code and COM Interfaces of VS.NET. There are many reasons why you have to choose option 2. The automation model allows you to have what is known as an "add-in" and can only do certain things. An add-in is actually a COM Component that implements the IDTExtensibilty2 interface. Using VSIP code, however, allows you to do just about anything. You become an actual "part" of VS.NET, through the use of what are known as Packages, or VsPackages. VSIP allows you to add your own splash screen or your own editor, or heck, even implement your own language. Its quite powerful but amazingly complex. It is hundreds of thousands of lines of code and based on tons and tons of COM Interfaces. The base example to just put up a new project type takes 66 files!!

I am using VSIP to have a COM component that implements IDTWizard. It turns out that lots of things in VS.NET are actually Wizards. My wizard calls one of VS.NET's wizards to launch a C# project that suppplies a WinForm and populates it with a base implementation of code for something. And I add toolbar tabs with custom tools and I add menus. A lot of this is of course better done through the Automation model. So I have been going through this laborious process of using C# to work out all the automation code I want, tweaking it, and then "porting" it all to C++/ATL COM code for inclusion in the ATL COM component that implements VSIP and IDTWizard. Yikes! I had forgotten how hard and time consuming COM was! I haven't done anything but Managed code for 2 years and had gotten used to how much easier it all is.

So what I wanted was a way to do my automation stuff in C# and then call the managed code through COM Interop. So I put everything in a C# class and then signed it. I then ran regasm /tlb on it to generate the CCW, register COM gunk in the Registry and generate the Type Library. I then imported the TLB into the C++ code and proceeded on to party on. Or so I thought. It turns out that, by default, COM Interop, does not expose type library information and worse than that, generates only IDispatch late-bound interfaces! I'll post why later but it's wrong, wrong, wrong. Late bound IDispatch interfaces are a legacy of VB3 and have no place other than Scripting languages in a modern world. I had to decorate the class with an attribute to "force" it to generate type info and generate a dual interface. Yeck.

Then it got worse. The DTE object in VS.NET Automation is full of bugs, missing functionality, and incomplete documentation. And there was still getting the types right across the boundary...More tomorrow...

Another day with VS.NET, .NET and VSIP. 

I think I have something real cool now and something to soon write an article about (I am doing one for Wrox right now on Web Forms and Managed C++). I have been doing a lot of work on an advanced development environment that will become a part of VS.NET (not an add-in). As I talked about much earlier, there is VSIP and the Automation model. VSIP is a real complicated beast. I can't talk much about it because of the agreements other than to see its big and complex. Productivity in creating things with it has been low. So I decided to use the Automation model in VS.NET to do stuff that I could do. I originally was doing things in the automation model with VB.NET, port to C# and then port back to ATL/C++ COM because VSIP is all COM based still. That's the weird thing about VSIP. There is this wonderful. modern XML-everything, whizzy environment for users to develop managed (and unmanaged C++) code in but the guts of VS.NET are still years of accumulated COM and old code!

.NET (which I have been working in for 2 years) has made me forget just how hard and tedious all this COM stuff is. When I ported, the one line of C# that went through 4 objects down in the automation model become a couple dozen lines of ATL COM (yes thats with Smart pointers too). Unfornately, VSIP is not managed code in any way and you can't even create an RCW for the Interfaces either! So, I ended up leaving the VSIP code in the COM component that implements IDTWizard and it launches the C# or VB.NET wizard that creates a User Control project. Now I needed to add default implementations of methods for the thing I was creating and a custom toolbar and tools. Time for automation.

I ended up coding a VB.NET component that manipulates the VS.NET DTE model to find the right place in the UserControl1.cs file and stick in the code on the fly. Why VB.NET? Because, believe or not, the Automation model in VS.NET has problems too! The NewLine() method for instance works in VB.NET but "is not implemented for V1 in C#!" Then I wrote a C# component to grab the VS.NET Toolbox, add a custom tab and some tools. Now to call it from ATL/C++ COM unmanaged code. Here are the steps:

  1. Create a C# or VB.NET class
  2. Generate a key for it - sn -k keyfile.snk

  3. Put an assembly directive at top of file

    [(Assembly: AssemblyKeyFile("keyfile.snk")]

  4. Compile

  5. regasm file.dll /tlb to generate the COM Type Library

  6. gacutil -i file.dll to place file in GAC

  7. Copy the generated typelibraries into the directory of your C++ project

  8. #import file.tlb no_namespaces named_guids and one other I can't remember

  9. Compile C++ code and you will have access to the CCW through the types in the imported tlb

Whew! After that, I now have a COM/ATL/C++ native component making calls to two different managed components in two different languages each handling the parts they are good in. Pretty cool?



© Copyright 2002 Sam Gentile.
Last update: 7/1/2002; 9:38:47 PM.

Click here to visit the Radio UserLand website.