Mailing List Archive

COM Question - QueryInterface?
I've got a (hopefully easy) question about python's COM support.

I'm developing a COM object in C++ which implements the COM collection
idiom - an Item method that returns another object. The code in Python
I'm using is something like this:

from win32com.client import Dispatch
drives = Dispatch("AmAccess.Drives")
drive = drives.Item("c:")
dir = drive.Item("some-area")

On this last line, I get an AttributeError for Item.

I think I know the reason why - the interface returned from Drives.Item
isn't a dual, it's an oleautomation compatible vtable interface.
IDispatch on that object is implemented separately. So, PythonCOM sees
the VT_UNKNOWN return type and wraps a PYIUnknown object around it. I
need to be able to do a QueryInterface for IDispatch.

How do I get Python to do that? There's a PyIID type, but apparently it
only works for class or progids. Anyone got any suggestions?

Thanks for any help,

-Chris
COM Question - QueryInterface? [ In reply to ]
Hi,

you get the IDispatch interface with this call prtoviding
you have an IUnknown.

>>>import pythoncom
>>>IUnk
<PyIUnknown at 0x3bf86a4 with obj at 0x837ab0>
>>>IUnk.QueryInterface(pythoncom.IID_IDispatch) # Query IDispatch
<PyIDispatch at 0x3bf4d54 with obj at 0x837ab0>
>>>IUnk.QueryInterface(pythoncom.IID_IDispatch).QueryInterface(pythoncom.IID
_IUnknown) # Query IUnkown again
<PyIUnknown at 0x3bf86a4 with obj at 0x837ab0>

You just have to get hold off at least one interface object.
If you use the wrapper classes generated by makepy you can get the
interface by using the _oleobj_ attribute e.g:

>>>from win32com.client import Dispatch
>>>drives = Dispatch("AmAccess.Drives")
>>>drives._oleobj_
<PyIDispatch at XXX with obj at XXX>

Hope this helps

Stefan



> ----------
> Von: Chris Tavares[SMTP:]
> Gesendet: Dienstag, 8. Juni 1999 03:17:58
> An: python-list@cwi.nl
> Betreff: COM Question - QueryInterface?
>
> I've got a (hopefully easy) question about python's COM support.
>
> I'm developing a COM object in C++ which implements the COM collection
> idiom - an Item method that returns another object. The code in Python
> I'm using is something like this:
>
> from win32com.client import Dispatch
> drives = Dispatch("AmAccess.Drives")
> drive = drives.Item("c:")
> dir = drive.Item("some-area")
>
> On this last line, I get an AttributeError for Item.
>
> I think I know the reason why - the interface returned from
> Drives.Item
> isn't a dual, it's an oleautomation compatible vtable interface.
> IDispatch on that object is implemented separately. So, PythonCOM sees
> the VT_UNKNOWN return type and wraps a PYIUnknown object around it. I
> need to be able to do a QueryInterface for IDispatch.
>
> How do I get Python to do that? There's a PyIID type, but
> apparently it
> only works for class or progids. Anyone got any suggestions?
>
> Thanks for any help,
>
> -Chris
>
>
>
COM Question - QueryInterface? [ In reply to ]
Chris Tavares <tavares@connix.com> wrote:

>I've got a (hopefully easy) question about python's COM support.
>
>I'm developing a COM object in C++ which implements the COM collection
>idiom - an Item method that returns another object. The code in Python
>I'm using is something like this:
>
>from win32com.client import Dispatch
>drives = Dispatch("AmAccess.Drives")
>drive = drives.Item("c:")
>dir = drive.Item("some-area")
>
>On this last line, I get an AttributeError for Item.
>
>I think I know the reason why - the interface returned from Drives.Item
>isn't a dual, it's an oleautomation compatible vtable interface.
>IDispatch on that object is implemented separately. So, PythonCOM sees
>the VT_UNKNOWN return type and wraps a PYIUnknown object around it. I
>need to be able to do a QueryInterface for IDispatch.

Your analysis sounds about right, this should give you the IDispatch interface
returned by querying for IID_IDispatch:

drive = drives.Item("c:")._oleobj_.QueryInterface(pythoncom.IID_IDispatch)

A better approach might be to make the interface dual? It sounds like you have
already tackled the painful bits of making your interface dual; implementing
IDispatch (under IID_IDispatch) and sticking to the oleautomation compatible
restrictions. Making it dual should be an easy step, and will avoid this and
several different non-python problems too.




Toby Dickenson
COM Question - QueryInterface? [ In reply to ]
Toby Dickenson wrote:

> Chris Tavares <tavares@connix.com> wrote:
>
> >I've got a (hopefully easy) question about python's COM support.
> >
> >I'm developing a COM object in C++ which implements the COM collection
> >idiom - an Item method that returns another object. The code in Python
> >I'm using is something like this:
> >
> >from win32com.client import Dispatch
> >drives = Dispatch("AmAccess.Drives")
> >drive = drives.Item("c:")
> >dir = drive.Item("some-area")
> >
> >On this last line, I get an AttributeError for Item.
> >
> >I think I know the reason why - the interface returned from Drives.Item
> >isn't a dual, it's an oleautomation compatible vtable interface.
> >IDispatch on that object is implemented separately. So, PythonCOM sees
> >the VT_UNKNOWN return type and wraps a PYIUnknown object around it. I
> >need to be able to do a QueryInterface for IDispatch.
>
> Your analysis sounds about right, this should give you the IDispatch interface
> returned by querying for IID_IDispatch:
>
> drive = drives.Item("c:")._oleobj_.QueryInterface(pythoncom.IID_IDispatch)
>
> A better approach might be to make the interface dual? It sounds like you have
> already tackled the painful bits of making your interface dual; implementing
> IDispatch (under IID_IDispatch) and sticking to the oleautomation compatible
> restrictions. Making it dual should be an easy step, and will avoid this and
> several different non-python problems too.
>
> Toby Dickenson

Toby,

Thanks. The reason that the interface in question isn't a dual is because my
object design depends quite heavily on having multiple interfaces. If you have
multiple duals, you end up with lots of problems with IDispatch, since you can't
safely implement more than one version of the same interface on a single object
(and lots of people have tried, REALLY HARD).

So what I'm doing is having multiple oleautomation compatible interfaces, and then
using a typelib-driven IDispatch implementation that I got from
http://www.sellsbrothers.com/tools/multidisp/index.html. This automagically merges
all my separate interfaces into a pseudo-object model. Really neat stuff, and
saves a TON of work.

Having tried that, I find that I now have access to IDispatch::Invoke. Well, what
I really wanted was win32com.client.dynamic.Dispatch. How do I get to the wrapped
IDispatch rather than the raw one?

-Chris
COM Question - QueryInterface? [ In reply to ]
(posted and cced to Chris)

Chris Tavares <tavares@connix.com> wrote:

>Thanks. The reason that the interface in question isn't a dual is because my
>object design depends quite heavily on having multiple interfaces. If you have
>multiple duals, you end up with lots of problems with IDispatch, since you can't
>safely implement more than one version of the same interface on a single object
>(and lots of people have tried, REALLY HARD).

This is a fallacy about IDispatch that I've heard from many sources, but it
certainly is not true.

One true statement is that you can only have one interface known as
IID_IDispatch. This causes a problem for scripting languages that can not
QueryInterface (or, worse, which QueryInterface behind your back).[

If you need to support this kind of client (VBScript, JScript, what else?
definitely not Python) then you need to implement IID_IDispatch with the union
of the methods from all your other interfaces. The page Chris mentions (below)
has a great summary of some solutions to this.

>So what I'm doing is having multiple oleautomation compatible interfaces, and then
>using a typelib-driven IDispatch implementation that I got from
>http://www.sellsbrothers.com/tools/multidisp/index.html. This automagically merges
>all my separate interfaces into a pseudo-object model. Really neat stuff, and
>saves a TON of work.

Follow that advice if you need to support those lesser scripting clients, or
don't if you don't.

In any case, there is still no reason not to make all your other interfaces dual
too. This should be an easy step. I am assuming you already have some IDL for
these interfaces? Change the oleautomation line to dual, and hook up the same
typelib-driven IDispatch implementation you are already using for IID_Dispatch.
If you are using ATL for this implementation then it all comes for free. The
advantages? You get easier access from Python, and in VB you get compile time
type safety.

In your specific example, the type library would say your collection object's
Item method returns an ITavaresDrive (or whatever) and python would use an
appropriate makepy-generated wrapper.

>Having tried that, I find that I now have access to IDispatch::Invoke. Well, what
>I really wanted was win32com.client.dynamic.Dispatch. How do I get to the wrapped
>IDispatch rather than the raw one?

drive = drives.Item("c:")._oleobj_.QueryInterface(pythoncom.IID_IDispatch)
win32com.client.Dispatch(drive)

(from memory)

I hope this helps,


Toby Dickenson
COM Question - QueryInterface? [ In reply to ]
Toby Dickenson wrote:

> (posted and cced to Chris)
>
> Chris Tavares <tavares@connix.com> wrote:
>
> >Thanks. The reason that the interface in question isn't a dual is because my
> >object design depends quite heavily on having multiple interfaces. If you have
> >multiple duals, you end up with lots of problems with IDispatch, since you can't
> >safely implement more than one version of the same interface on a single object
> >(and lots of people have tried, REALLY HARD).
>
> This is a fallacy about IDispatch that I've heard from many sources, but it
> certainly is not true.
>
> One true statement is that you can only have one interface known as
> IID_IDispatch. This causes a problem for scripting languages that can not
> QueryInterface (or, worse, which QueryInterface behind your back).[
>

I would disagree that this is a fallacy. It DOES cause problems for scripting languages
that won't do QI, but there's another client that can do a QI behind your back - the
COM remoting layer. You've got the possibility of some really wierd bugs that don't
show up in inproc that jump up and bite you when you go oop or remote.

>
> If you need to support this kind of client (VBScript, JScript, what else?
> definitely not Python) then you need to implement IID_IDispatch with the union
> of the methods from all your other interfaces. The page Chris mentions (below)
> has a great summary of some solutions to this.
>
> >So what I'm doing is having multiple oleautomation compatible interfaces, and then
> >using a typelib-driven IDispatch implementation that I got from
> >http://www.sellsbrothers.com/tools/multidisp/index.html. This automagically merges
> >all my separate interfaces into a pseudo-object model. Really neat stuff, and
> >saves a TON of work.
>
> Follow that advice if you need to support those lesser scripting clients, or
> don't if you don't.
>
> In any case, there is still no reason not to make all your other interfaces dual
> too. This should be an easy step. I am assuming you already have some IDL for
> these interfaces? Change the oleautomation line to dual, and hook up the same
> typelib-driven IDispatch implementation you are already using for IID_Dispatch.
> If you are using ATL for this implementation then it all comes for free. The
> advantages? You get easier access from Python, and in VB you get compile time
> type safety.
>

I understand the argument you're making. To be honest, I don't expect anyone other than
me to call these objects from Python - heck, my coworkers are still doing database apps
in C++!

I don't want to make the interfaces dual. Just chalk it up to stubborness, I guess. <G>
And in VB I've already got type safety.

>
> In your specific example, the type library would say your collection object's
> Item method returns an ITavaresDrive (or whatever) and python would use an
> appropriate makepy-generated wrapper.
>
> >Having tried that, I find that I now have access to IDispatch::Invoke. Well, what
> >I really wanted was win32com.client.dynamic.Dispatch. How do I get to the wrapped
> >IDispatch rather than the raw one?
>
> drive = drives.Item("c:")._oleobj_.QueryInterface(pythoncom.IID_IDispatch)
> win32com.client.Dispatch(drive)
>
> (from memory)
>

Thanks, I think this will do the trick!

>
> I hope this helps,
>
> Toby Dickenson

Sure does!

-Chris