OLE automation (IDispatch) support in IronPython

IronPython 1.X

IronPython 1.X supported COM interop by building on top of the COM interop support built into the CLR. This relies on the use of interop assemblies for managed code to access COM objects. The interop assembly can be accessed in different ways:

  1. clr.AddReference("interopAssembly") - This is the preferred mechanism so that the interop assembly does not have to be created multiple times. The down-side is that it complicates deployment. You have to ensure that the interop assembly exists on the machine.
  2. Having IronPython automatically generate it on the fly - if you have a OLE automation object, IronPython tries to find its type library (TLB) and then to convert the TLB to an interop assembly on the fly using the TypeLibConverter class. The advantage is that this works seamlessly as long as there is a type library on the machine. The down-side is that this conversion can take a long time for large TLB files.

This is how Word could be accessed in IronPython 1.X. It requires the interop assembly Microsoft.Office.Interop.Word.dll to be available on the machine.

c:\>ipy.exe
IronPython 2.0 Beta (2.0.0.1000) on .NET 2.0.50727.1433
Copyright (c) Microsoft Corporation. All rights reserved.
>>> import clr
>>> clr.AddReference("Microsoft.Office.Interop.Word") # load interop assembly
>>> from Microsoft.Office.Interop.Word import ApplicationClass
>>> word = ApplicationClass() # load class defined in interop assembly
>>> word.Visible = True # this works via CLR's COM interop support
>>> doc = word.Documents.Add()
>>> doc.Range().Text = "Hello from IronPython"
>>> word.Quit()
>>>

IronPython 2.0

IronPython 2.0 has added support for interacting with OLE automation objects using the IDispatch interface. This completely eliminates the need for interop assemblies. This is the same mechanism that VBA late-bound code and also WSH use to interact with OLE automation object. This feature can currently be accessed using the -X:PreferComDispatch command line option.

Here is an interactive session showing access to Word. There are no interop assemblies in the picture.

c:\>ipy.exe -X:PreferComDispatch
IronPython 2.0 Beta (2.0.0.1000) on .NET 2.0.50727.1433
Copyright (c) Microsoft Corporation. All rights reserved.
>>> import clr
>>> import System
>>> wordTypeLibGuid = System.Guid("00020905-0000-0000-C000-000000000046")
>>> clr.AddReferenceToTypeLibrary(wordTypeLibGuid)
>>> from Word import Application
>>> word = Application() # this uses Type.GetTypeFromCLSID and Activator.CreateInstance under the hood
>>> word.Visible = True # this uses IDispatch.Invoke
>>> doc = word.Documents.Add()
>>> doc.Range().Text = "Hello from IronPython"
>>> word.Quit()
>>>

The feature is not complete yet, and so is not currently (April 08) enabled by default. The default behavior is still the same as IronPython 1.X. I can't say for sure when we will enable it by default, but its already quite stable for many real-world uses. We run all of our COM tests in both modes - using interop assemblies and using IDispatch. There are a few differences between the two cases in the minute details, but the mainline scenarios work well in both. This feature is implemented in the DLR, and so should be accessible from all DLR-based languages with little effort on the part of the language-implementors.