Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.python > #100588 > unrolled thread
| Started by | jfong@ms4.hinet.net |
|---|---|
| First post | 2015-12-18 00:41 -0800 |
| Last post | 2015-12-18 03:15 -0800 |
| Articles | 3 — 2 participants |
Back to article view | Back to comp.lang.python
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
| From | jfong@ms4.hinet.net |
|---|---|
| Date | 2015-12-18 00:41 -0800 |
| Subject | Problem 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]
| From | eryk sun <eryksun@gmail.com> |
|---|---|
| Date | 2015-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]
| From | jfong@ms4.hinet.net |
|---|---|
| Date | 2015-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