Getting a ValueError with comtypes

W

winkatl1213

Hello,

I am working with comtypes to interface Microsoft's DirectShow library.

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.

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?

Thanks in advance,

Jeff
 
T

Thomas Heller

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
 
W

winkatl1213

Thomas,

Thanks a ton for the quick response.

I called GetModule('quartz.dll'), and now I can at least call
IMediaControl::Run. I get another error, but that's my problem (I
don't have the graph set correctly yet).

You mentioned that you sometimes create a type library for creating the
interface wrappers.

Would you mind sharing with me how you do this?

I seem to recall a thread on ctypes-users where you were looking for a
method to do this. I can't seem to locate what you conclusion was.

By the way, I've been using ctypes and comtypes quite a bit lately, and
I just wanted to say that they are both excellent.

Now if only I had an equivalent way to access C++ dlls, I'd no longer
have to write typemaps in SWIG.

While I'm at it, I thought I would ask you a separate completely
unrelated question.

I have a C++ library wrapped with SWIG. One member function takes a
void* to a buffer.

I want to allocate this buffer using ctypes and pass it to my SWIG
wrapper, but I've been struggling to get it to work.

I tried passing in the addressof, and then casting it back in my SWIG
wrapper, but this doesn't work. Do you have any suggestions on this?

I've also thought about using a numpy array, since this is supported in
both SWIG and ctypes.

Thanks again for your help.,

Jeff

Thomas said:
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
 
T

Thomas Heller

Thomas,

Thanks a ton for the quick response.

I called GetModule('quartz.dll'), and now I can at least call
IMediaControl::Run. I get another error, but that's my problem (I
don't have the graph set correctly yet).

You mentioned that you sometimes create a type library for creating the
interface wrappers.

Would you mind sharing with me how you do this?

Nothing fancy: I compile them with midl.
I seem to recall a thread on ctypes-users where you were looking for a
method to do this. I can't seem to locate what you conclusion was.

By the way, I've been using ctypes and comtypes quite a bit lately, and
I just wanted to say that they are both excellent.
Thanks!

Now if only I had an equivalent way to access C++ dlls, I'd no longer
have to write typemaps in SWIG.

While I'm at it, I thought I would ask you a separate completely
unrelated question.

I have a C++ library wrapped with SWIG. One member function takes a
void* to a buffer.

I want to allocate this buffer using ctypes and pass it to my SWIG
wrapper, but I've been struggling to get it to work.

I tried passing in the addressof, and then casting it back in my SWIG
wrapper, but this doesn't work. Do you have any suggestions on this?

Which object does the SWIG wrapper expect? Would a bufferobject suffice?
If this is the case, you could call buffer() on a ctypes object, maybe one
created with 'ctypes.create_string_buffer(size_in_bytes)'. Every ctypes
type instance supports the buffer protocol.
I've also thought about using a numpy array, since this is supported in
both SWIG and ctypes.

That might also work.

Thomas
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,764
Messages
2,569,567
Members
45,041
Latest member
RomeoFarnh

Latest Threads

Top