COM Interop in C# 4.0

Wow, it’s been a while since I’ve last posted! Don’t worry, I’m still alive and kickin’, and we’re still workin’ on cool stuff for y’all to use.

Let’s take a bit of a recap of how far we’ve come. We’ve chatted about dynamic binding in C# and how that all plays in with the DLR, and about named and optional arguments and how they change the way methods are bound. The only other major piece in C# 4.0 is this notion of COM interop. We chatted about how dynamic really is a gateway to interop with different object models and languages (ie interacting with dynamic languages, dynamic object models, javascript objects, HTML DOM etc), but in C# 4.0, we want to go a bit further and provide you a few more tools to help make your interop life much easier.

These remaining features that we’ll chat about all have a strong tie to the COM world – that is, the features themselves require that the objects that you’re playing with are COM objects. How do we determine that? Well, you’ll soon find out!

Keep on rockin’ in a… COM… world!

Alright, I admit it – I’m a Neil Young fan. The man wrote some great tunes! Anyway, the point is that Rock’n Roll ain’t goin’ nowhere. And either is COM. No matter how hard we try to get rid of it, it just won’t die! So we decided this time around that instead of trying to beat ‘em, we might as well join ‘em.

We’ve therefore created several features that are geared towards making your COM programming experience much easier. First let me list them:

  1. Passing non-ref arguments to by-ref parameters (aka COM omit ref in our world)
  2. Indexed properties
  3. No PIA deployment

The first two of these are comparatively smaller features from a complexity standpoint, so we’ll tackle those one at a time. We’ll discuss the No PIA feature in length in the several posts following.

Passing non-ref arguments to by-ref parameters

The first feature is really an acknowledgement that the APIs generated for COM interop are quite poor. For those of you who have worked in any amount of detail with the Office PIAs, you’ll quickly realize that for some reason, just about everything is passed around by ref.

This can get quite tiresome! Lets look at a quick Office example.

 static void Main()
{
    Word.Application app = new Word.Application();
    object m = Type.Missing;
    app.Documents.Add(ref m, ref m, ref m, ref m);
}

This is such typical code! I have to struggle with the type system to make it happy, just to add a simple Word document!

C# 4.0 makes this easier. The compiler will now determine that you’re working with a COM object by looking at the attributes of the type of that object, and checking to see if it has the [ComImport] attribute. Once it determines that you indeed are working with a COM object, it then gives you the ability to pass arguments to the method, index or property (yes, properties can have arguments a la indexed properties! We’ll talk about that later!) without giving them by ref.

This is really just compiler syntactic sugar – the compiler does the work to generate the temporaries for you, and slot them in place of the actual arguments. That means that in the following code, call (1) gets transformed into call (2).

 static void Main()
{
    Word.Application app = new Word.Application();
    // (1) Your initial call.
    app.Documents.Add(Type.Missing, Type.Missing, Type.Missing, Type.Missing);

    // (2) Compiler generates locals and inserts them.
    object m = Type.Missing;
    app.Documents.Add(ref m, ref m, ref m, ref m);
}

The great thing about this too, is that with the introduction of named and optional arguments, and using the fact that the feature generates Type.Missing in place of default values for object on COM types, we can simply remove the arguments altogether!

 static void Main()
{
    Word.Application app = new Word.Application();
    // (1) Your optional-parameter-omitted initial call.
    app.Documents.Add();

    // (2) Compiler generates locals and inserts them.
    object m = Type.Missing;
    app.Documents.Add(ref m, ref m, ref m, ref m);
}

Pretty cool stuff huh? Definitely makes programming against the Office APIs much nicer. The added bonus is that the IDE helps you out by letting you know that the parameters are optional, indicating that you can omit them, and indicating what the default value used in place will be.

So why now?

Let’s get into a bit of a philosophy discussion now, about why we’re doing all these different COM interop features now. In the past, we’ve been asked for these features – nay, we even pushed back against some of them.

For example, indexed properties is something that the VB language has had support for for quite some time now, but C# had decided that they weren’t the right way to go. Our standpoint was (and still is!) that the programming paradigm ought to be that the property is accessed, and that it is the thing that should supply the indexing.

So why are we adding all these features in now?

Well, for starters, COM’s pretty entrenched in the application programming world today. Many developers are having to struggle with the COM APIs and Office programming models every day, and it just doesn’t look like that model is going to be replaced, or will go away any time soon.

Next, C# 4.0 is really an interop release. Our focus this time around was to be able to interop with different programming languages and programming models. It seemed only fitting that one of the largest programming models still out there ought to be pretty high up on our list of priorities.

Dynamic binding allows for ease of interop with other object models and dynamic languages. The ability to use named and optional arguments allows ease of interop with legacy libraries like COM which have a lot of optional parameters, and large parameter lists. The introduction of the DLR, whose sole purpose is to provide a common runtime for interop with dynamic languages. All of these point us towards interop, and combined with the knowledge that COM interop has been a big pain point for our users really tipped the scale to pushing more interop features out this time around.

Agree? Disagree? As always, with philosophy things (and with everything else for that matter), I’d love to get your feedback. Until then, happy coding!

kick it on DotNetKicks.com