Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.python > #100588 > unrolled thread

Problem on ctypes arguments in a DLL function

Started byjfong@ms4.hinet.net
First post2015-12-18 00:41 -0800
Last post2015-12-18 03:15 -0800
Articles 3 — 2 participants

Back to article view | Back to comp.lang.python


Contents

  Problem on ctypes arguments in a DLL function jfong@ms4.hinet.net - 2015-12-18 00:41 -0800
    Re: Problem on ctypes arguments in a DLL function eryk sun <eryksun@gmail.com> - 2015-12-18 04:24 -0600
      Re: Problem on ctypes arguments in a DLL function jfong@ms4.hinet.net - 2015-12-18 03:15 -0800

#100588 — Problem on ctypes arguments in a DLL function

Fromjfong@ms4.hinet.net
Date2015-12-18 00:41 -0800
SubjectProblem on ctypes arguments in a DLL function
Message-ID<2331461b-cf4c-479c-8380-ddea3b7e7878@googlegroups.com>
I am trying to use the libusb-win32 v1.2.6.0 with Win7. I wrote a test program(showing below) but stuck with a strange problem. Here is the result:
----------------------------
D:\Work\Python34>python
Python 3.4.3 (v3.4.3:9b73f1c3e601, Feb 24 2015, 22:43:06) [MSC v.1600 32 bit (In
tel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import libusb_u2aTest as u2a
0x10c4
0x1
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "D:\Work\Python34\libusb_u2aTest.py", line 364, in <module>
    pHDL = _lib.usb_open(pDevice)
ValueError: Procedure probably called with too many arguments (4 bytes in excess
)
>>>
-----------------
I replace the troubled line with a "pass" to make the loading success, then to check the type of "pDevice", it's correct.

>>> u2a.pDevice
<libusb_u2aTest.LP__usb_device object at 0x017F0120>

It seems no reason that this call can be in trouble:-( Any hint was appreciated. Thanks ahead.


libusb_u2aTest.py listing:
-----------------------------
from ctypes import *
_lib = windll.LoadLibrary("C:\\Windows\\System32\\libusb0.dll")

_PATH_MAX = 512

### Data structures...
class _usb_device_descriptor(Structure):
    _fields_ = [('bLength', c_uint8),
                ('bDescriptorType', c_uint8),
                ('bcdUSB', c_uint16),
                ('bDeviceClass', c_uint8),
                ('bDeviceSubClass', c_uint8),
                ('bDeviceProtocol', c_uint8),
                ('bMaxPacketSize0', c_uint8),
                ('idVendor', c_uint16),
                ('idProduct', c_uint16),
                ('bcdDevice', c_uint16),
                ('iManufacturer', c_uint8),
                ('iProduct', c_uint8),
                ('iSerialNumber', c_uint8),
                ('bNumConfigurations', c_uint8)]

class _usb_device(Structure): pass
class _usb_bus(Structure): pass
_usb_device._fields_ = [('next', POINTER(_usb_device)),
                        ('prev', POINTER(_usb_device)),
                        ('filename', c_int8 * _PATH_MAX),
                        ('bus', POINTER(_usb_bus)),
                        ('descriptor', _usb_device_descriptor),
                        #('config', POINTER(_usb_config_descriptor)), # not implemented yet
                        ('config', POINTER(c_int)),  # to ease this test
                        ('dev', c_void_p),
                        ('devnum', c_uint8),
                        ('num_children', c_ubyte),
                        ('children', POINTER(POINTER(_usb_device)))]

_usb_bus._fields_ = [('next', POINTER(_usb_bus)),
                    ('prev', POINTER(_usb_bus)),
                    ('dirname', c_char * _PATH_MAX),
                    ('devices', POINTER(_usb_device)),
                    ('location', c_uint32),
                    ('root_dev', POINTER(_usb_device))]

_usb_dev_handle = c_void_p


### Function prototype...
# struct usb_bus *usb_get_busses(void);
_lib.usb_get_busses.restype = POINTER(_usb_bus)

# usb_dev_handle *usb_open(struct usb_device *dev);
_lib.usb_open.argtypes = [POINTER(_usb_device)]
_lib.usb_open.restype = _usb_dev_handle


### Test start...
_lib.usb_init()
_lib.usb_find_busses()
_lib.usb_find_devices()
pBus = _lib.usb_get_busses()
if bool(pBus):
    pDevice = pBus[0].devices
    if bool(pDevice):
        print(hex(pDevice[0].descriptor.idVendor))
        print(hex(pDevice[0].descriptor.idProduct))

if pDevice[0].descriptor.idVendor == 0x10c4 and \
   pDevice[0].descriptor.idProduct == 0x0001:
    pHDL = _lib.usb_open(pDevice)  # <--this line is in trouble

[toc] | [next] | [standalone]


#100595

Fromeryk sun <eryksun@gmail.com>
Date2015-12-18 04:24 -0600
Message-ID<mailman.52.1450434339.30845.python-list@python.org>
In reply to#100588
On Fri, Dec 18, 2015 at 2:41 AM,  <jfong@ms4.hinet.net> wrote:
> ValueError: Procedure probably called with too many arguments (4 bytes in excess

The function's calling convention is x86 cdecl (CDLL, caller stack
cleanup), but you're using the x86 stdcall convention (WinDLL, callee
stack cleanup). For a 64-bit process they're actually the same, but
you're using 32-bit Python, so you have to pay attention to the
convention.

> _lib = windll.LoadLibrary("C:\\Windows\\System32\\libusb0.dll")

It should simply be

    _lib = CDLL('libusb0')

windll/WinDLL is the wrong calling convention. Everything else is just
a waste of keystrokes. windll.LoadLibrary is an inferior way to call
WinDLL, since it can't pass constructor arguments such as use_errno or
use_last_error. The System32 directory is on the DLL search path, and
Windows will add the .dll extension for you.

The calling convention is declared in the header file lusb0_usb.h [1].
For example:

    struct usb_bus *usb_get_busses(void);

Notice there's no mention of __stdcall there, so it's using the
default cdecl convention.

> _usb_dev_handle = c_void_p

You'll be better off using

    class _usb_dev_handle(Structure):
        pass

    _usb_dev_handle_p = POINTER(_usb_dev_handle)

This provides stronger type safety. c_void_p is too permissive. It's
easier to debug a ctypes ArgumentError than a memory access violation
or data corruption.

[1]: http://sourceforge.net/p/libusb-win32/code/413/tree/trunk/libusb/src/lusb0_usb.h

[toc] | [prev] | [next] | [standalone]


#100597

Fromjfong@ms4.hinet.net
Date2015-12-18 03:15 -0800
Message-ID<054c6154-fc64-438a-8c4f-4c0b576d0c63@googlegroups.com>
In reply to#100595
eryk sun at 2015/12/18  UTC+8 6:26:02PM wrote:
> The function's calling convention is x86 cdecl (CDLL, caller stack
> cleanup), but you're using the x86 stdcall convention (WinDLL, callee
> stack cleanup). For a 64-bit process they're actually the same, but
> you're using 32-bit Python, so you have to pay attention to the
> convention.
> 
> > _lib = windll.LoadLibrary("C:\\Windows\\System32\\libusb0.dll")
> 
> It should simply be
> 
>     _lib = CDLL('libusb0')
> 
> windll/WinDLL is the wrong calling convention. Everything else is just
> a waste of keystrokes. windll.LoadLibrary is an inferior way to call
> WinDLL, since it can't pass constructor arguments such as use_errno or
> use_last_error. The System32 directory is on the DLL search path, and
> Windows will add the .dll extension for you.
> 
> The calling convention is declared in the header file lusb0_usb.h [1].
> For example:
> 
>     struct usb_bus *usb_get_busses(void);
> 
> Notice there's no mention of __stdcall there, so it's using the
> default cdecl convention.

Hi! eryk, thank you very much. No idea how long I will take to get out of this gutter if not have your hint. I should pay more attention on keyword __stdcall in the header file.

> > _usb_dev_handle = c_void_p
> 
> You'll be better off using
> 
>     class _usb_dev_handle(Structure):
>         pass
> 
>     _usb_dev_handle_p = POINTER(_usb_dev_handle)
> 
> This provides stronger type safety. c_void_p is too permissive. It's
> easier to debug a ctypes ArgumentError than a memory access violation
> or data corruption.
> 
> [1]: http://sourceforge.net/p/libusb-win32/code/413/tree/trunk/libusb/src/lusb0_usb.h

I think I am still in the kindergarten, not enter the gate of python school yet:-( much things to learn.

[toc] | [prev] | [standalone]


Back to top | Article view | comp.lang.python


csiph-web