我在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 import windll
libA = windll.LoadLibrary(“c:\ ctypestest \ test.dll”)
A类: def init (个体经营): 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命令提示符下,我执行以下操作 -
导入包装为w ---->工作正常
a = w.A() ----> works fine
a.some_func() ----> Error
libA.A_someFunc(self.obj)
ValueError:可能使用过多参数调用过程。(超出4个字节)
请帮忙。
提前感谢,
答案 0 :(得分:2)
您的导出使用的是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
个实例。这些在Windows中更有用,它自动提供.dll扩展名。例如,您可以使用cdll.test.A_new
。当像这样使用时,cdll
缓存加载的CDLL
实例,后者又缓存函数指针。
由于上述缓存,请避免在创建库时使用全局加载程序实例。您对函数指针的argtypes
,restype
和errcheck
定义可能与其他库冲突。而是使用CDLL
或私有加载程序,例如cdll = LibraryLoader(CDLL)
。
此外,cdll.LoadLibrary
返回CDLL
的非缓存实例。没有理由将其称为代替直接使用CDLL
。
答案 1 :(得分:0)
它应该与python中的任何对象创建相同:
some_var = A()