通过 ctypes 使用扩展 dll 中的类需要帮助
Posted
技术标签:
【中文标题】通过 ctypes 使用扩展 dll 中的类需要帮助【英文标题】:help required using a class in extension dll through ctypes 【发布时间】:2011-08-23 12:56:18 【问题描述】:我在 Visual Studio 中编写了以下代码来创建扩展 dll。
class A
public:
void someFunc()
;
extern "C" __declspec(dllexport) A* A_new()
return new A();
extern "C" __declspec(dllexport) void A_someFunc(A* obj)
obj->someFunc();
extern "C" __declspec(dllexport) void A_destruct(A* obj)
delete obj;
我想使用 ctypes 在 python 中使用 A 类。我在 wrapper.py 中写了以下代码 --
从 ctypes 导入windll
libA = windll.LoadLibrary("c:\ctypestest\test.dll")
A 类: def 初始化(自我): self.obj = libA.A_new()
def __enter__(self):
return self
def __exit__(self):
libA.A_destruct(self.obj)
def some_func(self):
libA.A_someFunc(self.obj)
在 python 2.7.1 命令提示符下,我执行以下操作 -
import wrapper as w ----> 工作正常
a = w.A() ----> works fine
a.some_func() ----> Error
libA.A_someFunc(self.obj)
ValueError: 过程可能调用了太多参数。(超过 4 个字节)
请帮忙。
提前致谢,
【问题讨论】:
How to use C++ classes with ctypes? 的可能重复项 你忘记了extern "C"
ctypes 使用的所有函数。恕我直言,删除 __del__
方法内的 c++ 对象。
【参考方案1】:
您的导出使用cdecl
调用约定,而不是stdcall
,因此您需要使用CDLL
而不是WinDLL
。
test.cpp:
#include <iostream>
#include <string>
using namespace std;
class A
string name;
public:
A(const string& name)
this->name = name;
cout << name << ": signing on" << endl;
~A()
cout << name << ": signing off" << endl;
void someFunc()
cout << name << ": calling someFunc" << endl;
;
extern "C"
__declspec(dllexport) A *A_new(const char *name)
return new A(string(name));
__declspec(dllexport) void A_someFunc(A *obj)
obj->someFunc();
__declspec(dllexport) void A_destruct(A *obj)
delete obj;
test.py:
import ctypes
lib = ctypes.CDLL('test.dll')
def opaque_ptr(name):
cls = type(name, (ctypes.Structure,), )
return ctypes.POINTER(cls)
class A(object):
_A = opaque_ptr('CPP_A')
lib.A_new.restype = _A
lib.A_new.argtypes = ctypes.c_char_p,
lib.A_destruct.argtypes = _A,
lib.A_someFunc.argtypes = _A,
def __init__(self, name, func=lib.A_new):
self._obj = func(name.encode('ascii'))
def __del__(self):
self.destruct()
def __enter__(self):
return self
def __exit__(self, exc_type, exc_value, traceback):
self.destruct()
def destruct(self, func=lib.A_destruct):
if self._obj:
func(self._obj)
self._obj = None
def some_func(self, func=lib.A_someFunc):
if not self._obj:
raise RuntimeError
func(self._obj)
with A('test') as a:
a.some_func()
输出:
test: signing on
test: calling someFunc
test: signing off
仅供参考,WinDLL
是 CDLL
的子类。唯一的变化是它在它创建的函数指针的标志中设置了_FUNCFLAG_STDCALL
,而不是_FUNCFLAG_CDECL
。
cdll
和 windll
是 LibraryLoader
实例。这些在自动提供 .dll 扩展名的 Windows 中更有用。例如,您可以使用cdll.test.A_new
。当这样使用时,cdll
缓存加载的CDLL
实例,然后缓存函数指针。
由于上述缓存,在创建库时避免使用全局加载器实例。您对函数指针的argtypes
、restype
和errcheck
定义可能与其他库发生冲突。而是使用CDLL
或私有加载程序,例如cdll = LibraryLoader(CDLL)
。
另外,cdll.LoadLibrary
返回CDLL
的非缓存实例。没有理由直接调用它来代替CDLL
。
【讨论】:
【参考方案2】:它应该与python中的任何对象创建相同:
some_var = A()
【讨论】:
实现__enter__
和__exit__
可能意味着他要使用with var=exr:
语句。
感谢您的帮助。我意识到我没有在此处粘贴正确的代码副本。类 A public: void someFunc() ; //extern "C" //告诉编译器为下一个作用域使用 C 链接。 // extern "C" __declspec(dllexport) A* A_new() return new A(); extern "C" __declspec(dllexport) void A_someFunc(void* obj) //obj->someFunc(); extern "C" __declspec(dllexport) void A_destruct(A* obj) 删除 obj;
感谢所有提供帮助的人。意识到我没有放正确的代码副本。我请求您重新阅读代码并在可能的情况下提供帮助。以上是关于通过 ctypes 使用扩展 dll 中的类需要帮助的主要内容,如果未能解决你的问题,请参考以下文章