Getting a ValueError with comtypes

Thomas Heller theller at python.net
Thu Oct 5 11:26:45 EDT 2006


winkatl1213 at yahoo.com schrieb:
> Hello,
> 
> I am working with comtypes to interface Microsoft's DirectShow library.

Cool, another one using comtypes!
 
> First, I found a Type Library on the internet that was created for
> accessing DirectShow from .NET.  It seems that DirectShow only comes
> with IDL files and no type library.

What I sometimes do is to compile the IDL files into a typelib just
for creating the comtypes interface wrappers.  This may be somewhat
dangerous because these typelibs should *not* be registered by accident,
so that they do not conflict with other typelibs.

Then, I found out with oleview that on my system the IMediaControl interface
is described in the 'ActiveMovie control type library (Ver 1.0)',
in c:\windows\system32\quartz.dll.  So I was able to create the wrapper
by calling comtypes.client.GetModule("quartz.dll") - it seems that windows
searches the $PATH to find type libraries.

> This got me started.
> 
> The following line imports the typelibrary and automatically generates
> a wrapper module for DirectShow.
> 
> ds = comtypes.client.GetModule('DirectShow.tlb')
> 
> Next, I can basically start with something like this:
> 
> graph = comtypes.CoCreateInstance(CLSID_FilterGraph, ds.IGraphBuilder,
> comtypes.CLSCTX_INPROC_SERVER)
> 
> I had to create the CLSID_FilterGraph parameter myself by doing the
> following:
> 
> CLSID_FilterGraph =
> comtypes.GUID('{e436ebb3-524f-11ce-9f53-0020af0ba770}')
> 
> One of the first issues I ran into was that the type library I found on
> the web didn't expose the IMediaControl interface.  So, using the
> generated wrapper as a template, I created my own wrapper:
> 
> class IMediaControl(comtypes.IUnknown):
>     _case_insensitive_ = True
>     _iid_ = comtypes.GUID('{56A868B1-0AD4-11CE-B03A-0020AF0BA770}')
>     _idlflags_ = []
> IMediaControl._methods_ = [
>     COMMETHOD([], HRESULT, 'Run'),
>     COMMETHOD([], HRESULT, 'Pause'),
>     COMMETHOD([], HRESULT, 'Stop'),
>     COMMETHOD([], HRESULT, 'StopWhenReady'),
>     COMMETHOD([], HRESULT, 'GetState',
>               (['in'], c_long, 'msTimeout'),
>               (['out'], POINTER(c_int), 'pfs' ))
> ]
> 
> This got me further.  Once I defined the interface, I get access to the
> interface by calling:
> 
> control = graph.QueryInterface(IMediaControl)
> 
> This seemed to work.  Once I got everything setup, I tried to use this
> interface.  For example:
> 
> control.Run()
> 
> This generates an exception:
> 
> Traceback (most recent call last):
>   File "<stdin>", line 1, in ?
>   File "ds.py", line 462, in play
>     control.Run()
> ValueError: Procedure probably called with not enough arguments (4
> bytes missing)
> 
> You can get errors like this when using ctypes if you use the wrong
> calling convention (CDLL versus WINDLL).
> 
> The method "Run" on the IMediaControl interface doesn't take any
> arguments.
> 
> I did notice that some wrapper code uses STDMETHOD versus COMMETHOD,
> but changing this didn't make any difference.
> 
> Can anyone explain what might be happening here, or offer some
> suggestions?

Your mistake here is that IMediaControl derives from IDispatch, not IUnknown.
So, control.Run() really calls the first IDispatch method, which is
GetTypeInfoCount(), which takes one argument ;-).

I'm not 100% sure the following code will work for you because I'm using
a comtypes version that's not yet committed to the repository, but it works
for me:

from comtypes.client import GetModule, CreateObject

# create and import the interface wrapper
ds = GetModule("quartz.dll")

# FilgraphManager is what the wrapper shows as coclass,
# you can pass that to CreateObject instead of a CLSID or ProgID.
# CreateObject calls QueryInterface for the 'most useful' interface,
# so usually there's no need to specify the interface you want:
fg = CreateObject(ds.FilgraphManager)

# this prints '0'
print fg.Run()

Thomas




More information about the Python-list mailing list