Reputation: 10101
Foreword: I'm pretty familiar with Python but had never touched C until a week ago... now I'm trying to speak to a motor controller using ctypes.
So i've been playing around with this particular function (VCS_GetProtocolStackSettings), and was unable to get it to work until just recently. My problem is that, although it's returning a '1' (ie is sucessful per the spec below), I seem unable to access the return parameters.
Here is the my code. You can see that I am storing the return parameters in pointers to uint32 objects, I just have no idea how to get at them.
lib=ctypes.WinDLL('C:\\Program Files (x86)\\maxon motor ag\\EPOS Positioning Controller\\EPOS2\\04 Programming\\Windows DLL\\EposCmd64.dll')
typeDict={ 'char': ctypes.c_char,
'char*': ctypes.c_char_p,
'__int8': ctypes.c_int8,
'BYTE': ctypes.c_uint8,
'short': ctypes.c_int16,
'WORD': ctypes.c_uint16,
'long': ctypes.c_int32,
'DWORD': ctypes.c_uint32,
'BOOL': ctypes.c_int32,
'HANDLE': ctypes.POINTER(ctypes.c_uint32)
}
def VCS_GetProtocolStackSettings(KeyHandle):
'''Returns the communication parameters 'baudrate and
'timeout'
'''
func=lib['VCS_GetProtocolStackSettings']
func.argtypes
func.restype=typeDict['BOOL']
pBaudrate=ctypes.pointer(typeDict['DWORD']())
pTimeout=ctypes.pointer(typeDict['DWORD']())
pErrorCode=ctypes.pointer(typeDict['DWORD']())
cKeyHandle=typeDict['HANDLE'](KeyHandle)
return func(KeyHandle,pBaudrate,pTimeout,pErrorCode)
Upvotes: 1
Views: 2037
Reputation:
If are testing ctypes, it's better to make a dummy DLL. For example, the prototype of your function is (I found it here):
Initialisation_DllExport BOOL __stdcall VCS_GetProtocolStackSettings(HANDLE KeyHandle, DWORD* pBaudrate, DWORD* pTimeout, DWORD* pErrorCode);
The dummy DLL would be:
/**
* file : lib.c
* build: cl /LD lib.c
*/
#include <windows.h>
#include <stdio.h>
#define DLL_EXPORT __declspec(dllexport)
#ifdef __cplusplus
extern "C" {
#endif
DLL_EXPORT BOOL __stdcall VCS_GetProtocolStackSettings(HANDLE KeyHandle,
DWORD* pBaudrate,
DWORD* pTimeout,
DWORD* pErrorCode);
#ifdef __cplusplus
};
#endif
DLL_EXPORT BOOL __stdcall VCS_GetProtocolStackSettings(HANDLE KeyHandle,
DWORD* pBaudrate,
DWORD* pTimeout,
DWORD* pErrorCode)
{
printf("%lu\n", (unsigned long) KeyHandle);
*pBaudrate = 1;
*pTimeout = 2;
*pErrorCode = 3;
return 4;
}
So our python code would be:
#!python
from ctypes import *
BOOL = c_int
DWORD = c_ulong
HANDLE = c_void_p
lib = WinDLL('./lib.dll')
# BOOL __stdcall VCS_GetProtocolStackSettings(HANDLE KeyHandle,
# DWORD* pBaudrate,
# DWORD* pTimeout,
# DWORD* pErrorCode);
VCS_GetProtocolStackSettings = lib['VCS_GetProtocolStackSettings']
VCS_GetProtocolStackSettings.restype = BOOL
VCS_GetProtocolStackSettings.argtypes = [HANDLE,
POINTER(DWORD),
POINTER(DWORD),
POINTER(DWORD)]
KeyHandle = HANDLE(123)
Baudrate = DWORD(0)
Timeout = DWORD(0)
ErrorCode = DWORD(0)
result = BOOL(VCS_GetProtocolStackSettings(KeyHandle,
byref(Baudrate),
byref(Timeout),
byref(ErrorCode)))
print(Baudrate.value)
print(Timeout.value)
print(ErrorCode.value)
print(result.value)
If you run it:
> python example.py
123
1
2
3
4
>
Upvotes: 1
Reputation: 178254
pBaudrate.contents.value
will access the value in the pointer, but you only really need a c_uint()
and pass it by reference to the function. Below is an example. It is also an example of making a function more "Pythonic" by throwing an exception on failure.
import ctypes
from ctypes import wintypes
lib = ctypes.WinDLL(dllnamehere)
lib.VCS_GetProtocolStackSettings.argtypes = [wintypes.HANDLE,wintypes.PDWORD,wintypes.PDWORD,wintypes.PDWORD]
lib.VCS_GetProtocolStackSettings.restype = wintypes.BOOL
def VCS_GetProtocolStackSettings(KeyHandle):
baudrate = wintypes.DWORD()
timeout = wintypes.DWORD()
errorcode = wintypes.DWORD()
result = lib.VCS_GetProtocolStackSettings(KeyHandle,ctypes.byref(baudrate),ctypes.byref(timeout),ctypes.byref(errorcode))
if not result:
raise RuntimeError('error code = {}'.format(errorcode.value))
return baudrate.value,timeout.value
P.S. Double check that WinDLL
is appropriate. Windows system DLLs use the __stdcall
calling convention, but many DLLs use __cdecl
calling convention and you would use CDLL
instead.
Upvotes: 2