Default
Google

Python and COM

Home Abstract Prerequisites Activities Status

Abstract

I have recently been playing with Python and COM on Windows 2000. Whilst the built-in help in PythonWin does go some way towards explaining the bizarre details of COM and the various common interfaces one might find, it is really necessary to go looking for concrete interface information from Microsoft, and I found it necessary to look in the source code of the various examples provided in the win32com package. My aim in this document is to give enough information to help readers avoid having to do the same!

Prerequisites

Perhaps the easiest way of obtaining Python for Windows platforms is to go to ActiveState and download their ActivePython package. You can alternatively visit the Python site, download Python and then go looking for the win32all extensions. I just did what was easiest, of course!

For the activites given below, you may need extra software such as Microsoft Outlook, although you probably won't be interested in playing with Outlook and Exchange if you don't have them.

Activities

Initialising Type Libraries

Whilst the win32com package provides a number of ways of querying and accessing COM interfaces with few obvious differences between them (provided you know the interface), it is usually more convenient when experimenting (particularly in PythonWin with its attribute completion feature) to know what methods and properties are really available for a given interface. This is where the "COM Makepy utility", accessible from the "Tools" menu in PythonWin, is useful. By selecting a particular type library and building the Python interfaces using this tool, much more information becomes available in PythonWin, and casual investigation of object interfaces becomes much easier.

Writing Clients

All client COM access starts with the following statement in your Python program:

import win32com.client

Typically, your program will then try and find an object to use. For example:

object = win32com.client.Dispatch("Outlook.Application")

This object will then refer to a "COM object" which can have methods invoked upon it and its attributes examined like any other Python object, although we may be "automating" a Windows application (such as Outlook) when we do this.

Outlook and Exchange

One of the supposedly irritating things about Microsoft Exchange Server is the way that it hides a lot of its internals and requires a fair amount of programming to let you get to things such as contact lists and address books. It's interesting to note that much advice is to be found on importing other systems' address books into Exchange but not as much on getting the addresses back out and into something else. (As if Microsoft think that you would want to, really!)

Anyway, this led me to write a small program to access Exchange's public address books through Outlook. If your organisation is running Exchange, you're probably required to run Outlook as well, and therefore automating Outlook is a valid strategy in accessing Exchange. One alternative for accessing certain types of information is to use the Active Directory Services API and/or LDAP, but I haven't been successful in that area.

Reminder: before starting the example, build the "Microsoft Outlook 9.0 Object Library" using the "COM Makepy utility".

Example

The "interactive address book" program (which you can download) uses MAPI (Messaging API) within Outlook to access mail resources. The first thing it does is to obtain a reference to the Outlook application's automation object and to enter the MAPI namespace:

o = win32com.client.Dispatch("Outlook.Application")
ns = o.GetNamespace("MAPI")

What this really does is beyond my level of interest, but it does allow us to access the "folder" hierarchy accessible within Outlook. You can see this hierarchy yourself by opening Outlook manually and bringing up the folder menu (which typically says "Inbox" or "Outlook Today" or something).

Folders and Items

The example program uses some fancy Python tricks to access the attributes of the "COM objects" it references, but in essence it looks up the folders and items available within each object:

# Refer to the folders within a given object...
subobject = object.Folders
# Refer to the items within a given object...
subobject = object.Items

Querying Interfaces

Now, how does one investigate the detail of each object? For example, how does one access the name of a folder? Firstly, it helps to know the interface that the object exposes, and this information can be found in two principal places:

Hopefully, however, the object that you are accessing is known well enough by PythonWin to permit some kind of attribute or method completion on it. You should only need to resort to the above when more detailed knowledge about a method or attribute is required. You can also try something like this:

dir(object.__class__)

The name of a folder can be accessed as follows:

object.Name # Where object refers to a folder.

Sequences

Of course, there can be many folders or items in a folder. How do we traverse this collection? The recommended way is arguably to use Python's sequence index notation, but beware: the first element's index apparently is not standard and can be 0 or 1. In Outlook's object model, the first element in such sequences is indeed indexed by 1, resulting in the following observations:

To access objects which behave like sequences, the following Python mechanisms can be used:

object[1]   # The first element.
len(object) # Return the number of elements.

The following mechanisms do not seem to work:

object[-1]  # Should be the last element, but instead we get an exception.
object[1:4] # Should slice the sequence, but instead we get an exception.

Summary

With the above information, the example program can access different levels of folders, query items and extract addresses to a file. By using the Parent attribute on any given folder, we can navigate upwards through the hierarchy without needing to keep references to places we have already explored.

Status

(June 1st, 2001)
Created this page.


Acquiring image from ProHosting Banner Exchange