在Python中使用ctypes与仅包含函数指针的C结构交互

2 投票
2 回答
2992 浏览
提问于 2025-04-16 04:57

我在一个动态链接库(dll)里有一个结构体,这个结构体里面只包含了一些函数指针(也就是虚函数表),我想在Python中和它互动(主要是为了测试)。不过,我在用ctypes的时候遇到了一些麻烦。

我现在有的是:

struct ITest  
{  
    virtual char const  *__cdecl GetName() = 0;  
    virtual void  __cdecl SetName(char const *name) = 0;  
};

/* Factory function to create 'real' Test object */  
extern "C" __declspec(dllexport) struct ITest * CALLCONV make_Test(char const * name); 

一个“真实”的测试对象会把这个结构体填充好。然后这个结构体会被编译成一个DLL(test.dll)。我希望在Python中能够调用一个工厂方法,得到指向我的测试结构体的指针,然后调用这个结构体里面的函数指针,但我就是搞不清楚用ctypes该怎么实现。有没有人能给我一些建议或者类似的例子,或者我应该使用像SWIG或Boost这样的工具吗?

谢谢大家的帮助。

2 个回答

1

ctypes的文档说,你可以通过一个地址来创建ctypes.PYFUNCTYPE。

如果你能获取到结构体中函数的地址,那么你就可以用ctypes.PYFUNCTYPE把它包装成一个Python函数,然后像调用普通的ctype函数一样去调用它。

我自己没有测试过,但我觉得这可能是你可以尝试的一个方向。

可以查看这个链接了解更多信息:http://docs.python.org/library/ctypes.html#ctypes.PYFUNCTYPE

希望这对你有帮助。

3

像这样的代码应该是一个不错的起点(我没有你的DLL文件,所以没法测试)。

from ctypes import Structure, CFUNCTYPE, POINTER, c_char_p, windll
class ITest(Structure):
    _fields_ = [
            ('GetName', CFUNCTYPE(c_char_p)),
            ('SetName', CFUNCTYPE(None, c_char_p)
        ]

test = windll.LoadLibrary('test.dll')
test.make_Test.restype = POINTER(ITest)

接下来,你需要调用make_Test()来获取结构体,然后尝试调用这些函数。你可以用类似这样的代码:

itest = test.make_Test().contents
itest.SetName('asdf')
print itest.GetName()

把DLL文件或者测试结果发给我,如果你还有问题,我可以提供更多帮助。

撰写回答