python - 如何使用基于 ctypes 和 ctypes 的枚举正确调用将“自定义枚举”作为参数的函数?
问题描述
我真的希望一些 Python/Ctypes/C 专家可以帮助我解决这个问题,这可能是我在使用 Python 与 C 库交互时对正确使用 Ctypes 的类型结构缺乏了解。
目标:我需要访问几个使用 ctypes 加载 DLL 并与之交互的库函数。这个想法在大多数情况下都很有效,但是很少有函数将枚举作为参数,而且这些枚举在涉及 int 类型时非常敏感。这是一个假的例子:
typedef enum led_property : uint8_t {
LED_OFF = 0
LED_POWER
}
int32_t configure_led(const led_property, const int32_t value)
这是函数接收的枚举类型,不仅适用于 uint8_t,还适用于 int32_t、int_64t 等。
从我在网上找到的一个 python 食谱中,我设法用 ctypes 类型“调整”了 python 枚举:
class EnumerationTypeUInt8(type(c_uint8)):
def __new__(metacls, name, bases, dict):
if not "_members_" in dict:
_members_ = {}
for key, value in dict.items():
if not key.startswith("_"):
_members_[key] = value
dict["_members_"] = _members_
cls = type(c_uint8).__new__(metacls, name, bases, dict)
for key, value in cls._members_.items():
globals()[key] = value
return cls
def __contains__(self, value):
return value in self._members_.values()
def __repr__(self):
return "<Enumeration {}>".format(self.__name__)
def EnumerationUInt8(c_uint8):
__metaclass__ = EnumerationTypeUInt8
_members_ = {}
def __init__(self, value):
for k, v in self._members_.items():
if v == value:
self.name = k
break
else:
raise ValueError("No enumeration member with value {}".format(value))
c_uint8.__init__(self, value)
@classmethod
def from_param(cls, param):
if isinstance(param, EnumerationUInt8):
if param.__class__ != cls:
raise ValueError("Can not mix enumeration members")
else:
return param
else:
return cls(param)
def __repr__(self):
return "<member {}={} of {}".format(self.name, self.value, self.__class__)
我正在加载库并装饰其功能,如下所示:
class LedProperty(EnumerationUInt8):
LED_OFF = c_uint8(0)
LED_POWER = c_uint8(1)
lib = "library.dll"
self._lib = CDLL(lib)
configure_led = self._lib.configure_led
configure_led.argtypes = [LedProperty, c_int32]
configre_led.restype = c_int32
问题是我尽我所能,但我永远无法正确调用 configure_led python 函数,大多数时候我得到以下错误:
ctypes.ArgumentError class 'ValueError' No enumeration member with value c_ubyte(1)
or
ctypes.ArgumentError class 'ValueError' No enumeration member with value 1
发生这种情况是因为我在调试时可以看到“EnumerationUInt8”“ self.members.items ()”总是一个空字典。所以可能这个带有 ctypes 的自定义枚举没有正确加载它们的成员。我总是以“else:return cls(param)”结尾
试过:
configure_led(LedProperty.LED_POWER, 5)
configure_led(LedProperty.LED_POWER.value, 5)
configure_led(c_uint8(LedProperty.LED_POWER), 5)
... 等等!似乎没有什么是正确的。
有谁知道如何使用 cytpes 类型正确声明枚举,然后使用这些枚举作为函数的参数?
观察者:我目前正在使用Python 3.8.3 在此先感谢!
解决方案
假设这个实现,test.cpp:
#include <stdint.h>
enum led_property : uint8_t {
LED_OFF = 0,
LED_POWER
};
extern "C" __declspec(dllexport) int32_t configure_led(enum led_property prop, int32_t value) {
return prop * value;
}
这将只允许第一个参数的 LED 值:
from ctypes import *
from enum import Enum,auto
class LED(Enum):
OFF = 0
POWER = auto() # autoincrement from last value
@classmethod
def from_param(cls,obj):
if not isinstance(obj,LED):
raise TypeError('not an LED enumeration')
return c_int8(obj.value)
dll = CDLL('./test')
dll.configure_led.argtypes = LED,c_int32
dll.configure_led.restype = c_int32
print(dll.configure_led(LED.OFF,5)) # prints 0
print(dll.configure_led(LED.POWER,5)) # prints 5
print(dll.configure_led(0,5)) # not an LED enumeration
推荐阅读
- c++-cli - C++/CLI 中的 ExpandoObject
- anchor - 如何用苗条粘在锚上?
- html - 如何找出站点密钥
- dataset - 如何在 TensorFlow 2 中为三元组挖掘创建和打乱数据集?
- amazon-web-services - 为什么 RDS 不使用 Amazon 根证书进行 SSL 连接
- asynchronous - 在异步函数参数中声明特征对象的关联类型
- java - 引起:org.hibernate.exception.SQLGrammarException:JDBC异常执行SQL
- angular - 是否有任何功能可以在第一个突出显示的搜索文本上自动滚动查找?
- jsf - xhtml 文件不起作用,但 html 文件可以正常工作
- c# - 从 Crystal Report 查看器中的每个页面获取内容并将其导出为 pdf