1

前言:我对 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)

在此处输入图像描述

4

2 回答 2

2

pBaudrate.contents.value将访问指针中的值,但您只需要 ac_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

PS仔细检查WinDLL是否合适。Windows 系统 DLL 使用__stdcall调用约定,但许多 DLL 使用__cdecl调用约定,而您会使用它CDLL

于 2013-01-19T20:35:31.283 回答
1

如果正在测试 ctypes,最好制作一个虚拟 DLL。例如,您的函数原型是(我在这里找到的):

     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
>
于 2013-01-19T21:09:37.407 回答