Discussion, code samples and video demos of new technologies; including Web 2.0 startups, Google AppEngine, Ruby on Rails, PHP, Visual Studio Team System, Team Foundation Server and .NET.

Friday, January 5, 2007

The Joys of C++/CLI

Hey guys,

I've been spending a lot of time programming against Windows Vista lately, and during that time I have really come to enjoy the second incarnation of managed C++, now called C++/CLI.

Unless you are really good at .NET marshalling, a lot of great Windows Vista features just aren't that accessible from .NET.  This is where C++/CLI really comes into its own.

A perfect example of this is when writing a preview handler in Windows Vista.  Preview handlers are lightweight viewers that give you a sneak peek at a file before opening it up.

You can enable preview handlers in Windows Explorer from the Organize menu as shown.

Once enabled, any document type with a preview handler will get triggered - Word 2007 is a good example.

The file that I am previewing is quite big - about 10MB - so it's nice to get a preview before starting up Word 2007 to open it up.

Preview Handlers are pretty easy to implement - but they do require that you implement a few COM interfaces.  The interfaces that you have to implement don't belong in type libraries that you can use tlbimp to generate .NET wrappers.

So, if you are using .NET, you have to craft your own COM interfaces (MSDN has an article about doing this for preview handlers), otherwise, you have to dust off your COM skills and get going with C++ :)

I've always been against hand crafting .NET interfaces for COM interfaces for a few reasons.  First, I absolutely abhor marshalling.  I'm no good at it, and I feel like I have to learn 2 things at once; I have to learn/re-learn how to marshal, as well as learning how to use whatever interface I'm using.  Second, I don't think the approach scales very well.  I'm always afraid that one day I will run into a COM interface that I absolutely don't know how to marshal.  Lastly, I'm impatient :) I hate having to take time to write marshalling code instead of my applicatio-specific code.

This is where C++/CLI becomes really handy.  To implement my preview handler, I first created an attributed ATL project for my COM server.

Attributes in ATL really clean up your code - for example, the declaration for my various DLL methods (DLLMain, DllRegisterServer, etc) is all taken care of with the following.

As soon as I build my project, my COM server will get registered.  No messy class factories or registration code to write.

To add a COM object, I just have to add a new class to my project and decorate it with the following attributes.

It's been years since I used ATL, so I didn't just crank this out on my own; I followed a nice walkthrough that the ATL team published. 

Note - in order to use the CLR in a ATL project, you have to adjust a few project settings; the walkthrough found here describes this nicely.

Once I had that, I just did some cutting-and-pasting from the Platform SDK preview handler sample to implement the interfaces I needed.  To be a preview handler, you need all of the interfaces shown below.

At first I found that list to be a bit intimidating, but the samples in the Platform SDK are quite good, so I was able to borrow a good amount of code to get going.  I don't want to kick off a pointless .NET vs C++ debate (I've been on both sides of that one), but one of the nice things about using C++/CLI is that you kind of get the best of both worlds.  When you're working with a COM-based technology like preview handlers, most of the samples will be in C++.  Since I'm using C++/CLI, I can just copy those right in.

Now since we are writing a preview handler, we need some visualization.  In my opinion, one area where C++ struggles a bit is in building user interfaces.  Win32, WTL, MFC are all great solutions, but I think it is fair to say they aren't the most approachable technologies.

I like using C# for building user interfaces - Winforms for 'regular' interfaces and WPF for more sophisticated ones.  Again, because we are using C++/CLI, we can do that.

To build the user interface for my preview handler, I just create a C# user control library with 1 user control.  Using the designer, I created a simple user control with 1 read-only, multi-line text box.

 

All I'm going to do in my preview handler is dump out some text.  This text is going to come from the Windows Shell through the preview handler infrastructure.  From the point of view of this user control, I don't really care where it comes from, I'm just going to take a string and display it, so I added one method called ShowPreview.

With our UI set, we can go back to the C++.  In order to reference our C# user control we can use the gcroot type in C++/CLI. 

Notice the ^ syntax, that denotes a 'handle' to a .NET object. 

The last bit of funny syntax is the gcnew keyword to instantiate the class.

With the ^ and gcnew, we can use this object just like any other C++ object.  Members are referenced with a -> just like we are used to.

A user control inherits from a Control, which exposes a Handle property.  That gives us a way to get the HWND's that the preview handler interfaces need.

Our user control will be a child of a HWND that is given to use through the IPreviewHandler interface.  A simple call to the SetParent() Win32 method will setup the parent-child relationship correctly.

The last bit of coding necessary is to pass the contents of our file to our user control.

The String class has a constructor that accepts BSTRs so we don't have to do any marshalling.

The end result is pretty basic, but does give an idea into what it's like to build a preview handler.

One of the reasons I decided to try C++/CLI is that I knew that if I got into trouble, I could always fall back to the excellent C# example in the MSDN article that I mentioned earlier :) 

That said, I'm pretty pleased with how C++/CLI gave me a way to mix what C++ and ATL do pretty well (COM, Shell Extensions, etc) with what .NET does pretty well (user interfaces, dnd design, etc).

I know the C++/CLI guys worked really hard on this second release of managed C++, here's to hoping that Vista gives their work an opportunity to really shine.

Thanks!

Eric.

2 Comments:

Anonymous Anonymous said...

Very nice. Just for comparison, it's also possible to do this purely in C#:
http://msdn.microsoft.com/msdnmag/issues/07/01/PreviewHandlers

January 31, 2007 8:08 AM

 
Blogger chakshu said...

Can this be used on Windows XP/2003 also? or Windows Vista is necessary?

September 17, 2007 4:55 AM

 

Post a Comment

Links to this post:

<< Home