如何使用 ctypes 和基于 ctypes 的枚举正确调用以“自定义枚举”作为参数的函数?

2023-12-14

我真的希望一些 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

发生这种情况是因为我在调试时可以看到“Enumeration UInt8”“self.members.items()”始终是一个空字典。因此,带有 ctypes 的自定义枚举可能没有正确加载其成员。我总是以“else: return cls(param)”结束

Tried:

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
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何使用 ctypes 和基于 ctypes 的枚举正确调用以“自定义枚举”作为参数的函数? 的相关文章

随机推荐