[Tutor] COM Interfaces

dominic.fox dominic.fox" <dominic.fox@ntlworld.com
Mon, 13 May 2002 20:20:40 +0100


Lloyd Kvam was kind enough to reply:

> Python depends on the registry entries to find the COM object it is
running.
> The name passed to Dispatch MUST exactly match the name in the registry.
You
> can't make it up.

Well, this is much like creating an object in, say, VBScript or JavaScript
by passing the progid to CreateObject(). You can't do much with
multiple-interface objects in JavaScript, to my knowledge; what I was
wondering was whether PyWin & c. managed to improve on the situation.

> I suspect that 'MSXML2.DOMDocument30' should be 'MSXML3.DOMDocument30'.
If you
> search your registry, you should be able to find the name.
>
> To run your VB COM object, you need to get it registered.  Then simply
pass
> the name you used to register it to dispatch, just like you did for MSXML.

I can do this without difficulty for single-interface objects, but not at
all for dual or multiple interface objects. Yesterday evening I coded up a
small-ish .dll to try some of these things out with. Getting instances of
the more conventional objects by progid was a doddle. There didn't seem to
be any way at all of using the multiple-interface ones.

Just to clarify: in VB you can do the following:

Class MyInterface

Public Sub DoSomethingExciting()
End Sub

---

Class InheritorTheFirst

Implements MyInterface

Private Sub MyInterface_DoSomethingExciting()

    Msgbox "Wow!"

End Sub

---

Class InheritorTheSecond

Implements MyInterface

Private Sub MyInterface_DoSomethingExciting()

    Msgbox "Whoopee!"

End Sub

---

and then...

Dim MyInstance As MyInterface
Set MyInstance = New InheritorTheSecond
MyInstance.DoSomethingExciting
Set MyInstance = New InheritorTheFirst
MyInstance.DoSomethingExciting

---

MyInterface is something like an abstract base class, which simply outlines
in skeleton form the COM interface that the other two classes will use. Just
to confuse matters, they are allowed to implement as many different
interfaces as they like; they are also allowed their own 'native' COM
interface as well. The specifics of how this is implemented escape me, but I
think it has to do with the way IUnknown and IDispatch are mapped to method
calls through whatever mechanism it is that VB uses. Whatever: it's ugly,
and Python is beautiful, so I feel as if I ought to be apologising for
bringing the matter up at all...

Now the question is, assuming I have created and registered a .dll
containing the above, and want to create an object in Python which behaves
like an instance of InheritorTheSecond, and want Python to know that I can
call MyInterface's methods on it, can I? If I can, how can I? You only get
to pass one progid to Dispatch. If it's the progid of MyInterface, you get
an instance of the base class which doesn't do anything. If it's the progid
of InheritorTheSecond, the "inherited" or "implemented" member functions are
invisible and can't be used.

For my own purposes, it would be easy enough just to eschew this technique;
or better still, write everything in Python to begin with. But there are
other libraries out there that I didn't write, can't obtain the source code
for, and might still want to use. Some of them (like MSHTML, which gives you
access to the DOM in Internet Explorer HTML documents) use multiple
interfaces fairly extensively. It would be useful to know whether I can use
them directly in Python, or whether I'd need to come up with a set of
simplified "wrapper" classes in VB for them first.

As an aside, the reason why VB *has* multiple interfaces is that it's a
statically typed language, which means amongst other things that, as in Java
and C++, the signatures of method function calls include the types of the
parameters being supplied (this might come as a surprise to some VB
programmers of my acquaintance, who use Variants for everything...). So if I
have a variety of different persistence mechanisms, say, which can all store
basic plain-text strings, I might want to have a method which writes a given
string in uppercase to any one of them, without needing to know what the
underlying mechanism is. If my method looks like this:

Public Sub writeUppercase( persistenceMechanism as IPersist, stringToWrite
as String)

    IPersist.writeString strconv( stringToWrite, vbUpperCase )

End Sub

then I can pass it an instance of any class that "implements" IPersist, be
it a wrapper for database access, textfile access, storing things in cells
in an Excel worksheet or whatever. In Python, which is dynamically typed,
all of this is pretty much redundant...although I did read somewhere an
article by a diehard Smalltalk enthusiast who nevertheless admitted,
vis-a-vis Java, that programming to interfaces sounded like quite a sensible
idea...

Dominic