通过 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

仅供参考,WinDLLCDLL 的子类。唯一的变化是它在它创建的函数指针的标志中设置了_FUNCFLAG_STDCALL,而不是_FUNCFLAG_CDECL

cdllwindllLibraryLoader 实例。这些在自动提供 .dll 扩展名的 Windows 中更有用。例如,您可以使用cdll.test.A_new。当这样使用时,cdll 缓存加载的CDLL 实例,然后缓存函数指针。

由于上述缓存,在创建库时避免使用全局加载器实例。您对函数指针的argtypesrestypeerrcheck 定义可能与其他库发生冲突。而是使用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 中的类需要帮助的主要内容,如果未能解决你的问题,请参考以下文章

ctypes 与 C 扩展

python中的ctypes,在DLL中调用函数的问题

php中的扩展解析

使用 ctypes 列出从 dll 导出的函数

Python调用windows下DLL详解 - ctypes库的使用

在 python 中的 byref 向量参数上使用 ctypes 进行 DLL 转换