我在 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;
}
Run Code Online (Sandbox Code Playgroud)
我想在python中使用ctypes来使用A类。我在wrapper.py中编写了以下代码——
从 ctypes 导入 Windll
libA = Windll.LoadLibrary("c:\ctypestest\test.dll")
A类: def init (self): 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)
Run Code Online (Sandbox Code Playgroud)
在 python 2.7.1 命令提示符下,我执行以下操作 -
import 包装器 as w ----> 工作正常
a = w.A() ----> works fine
a.some_func() ----> Error
libA.A_someFunc(self.obj)
Run Code Online (Sandbox Code Playgroud)
ValueError:调用过程可能使用了太多参数。(超出 4 个字节)
请帮忙。
提前致谢,
您的导出使用cdecl调用约定,而不是,stdcall因此您需要使用。CDLLWinDLL
测试.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;
}
}
Run Code Online (Sandbox Code Playgroud)
测试.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()
Run Code Online (Sandbox Code Playgroud)
输出:
test: signing on
test: calling someFunc
test: signing off
Run Code Online (Sandbox Code Playgroud)
仅供参考,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直接使用。