使用ctypes提取返回参数

时间:2013-01-19 20:12:05

标签: python pointers ctypes

前言:我对Python非常熟悉,但直到一周前从未接触过C ......现在我正在尝试使用ctypes与电机控制器对话。

所以我一直在玩这个特定的功能(VCS_GetProtocolStackSettings),直到最近才能让它工作。我的问题是,虽然它返回'1'(即根据下面的规范成功),但我似乎无法访问返回参数。

这是我的代码。您可以看到我将返回参数存储在指向uint32对象的指针中,我只是不知道如何获取它们。

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)

enter image description here

2 个答案:

答案 0 :(得分:2)

pBaudrate.contents.value将访问指针中的值,但您只需要c_uint()并通过引用函数传递它。以下是一个例子。它也是通过在失败时抛出异常使函数更“Pythonic”的一个例子。

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。仔细检查WinDLL是否合适。 Windows系统DLL使用__stdcall调用约定,但许多DLL使用__cdecl调用约定,而您将使用CDLL代替。

答案 1 :(得分:1)

如果正在测试ctypes,最好制作一个虚拟DLL。例如,函数的原型是(我发现它here):

     Initialisation_DllExport BOOL __stdcall VCS_GetProtocolStackSettings(HANDLE KeyHandle, DWORD* pBaudrate, DWORD* pTimeout, DWORD* pErrorCode); 

虚拟DLL将是:

/**
 * 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;
}

所以我们的python代码是:

#!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)

如果你运行它:

> python example.py
123
1
2
3
4
>