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