2011-08-23 66 views
0

我已经在Visual Studio中编写了下面的代码来创建一个扩展dll。帮助需要使用类扩展dll通过ctypes

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 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) 

在蟒2.7.1命令提示i执行以下操作 -

进口的包装为w ---->工作正常

a = w.A()   ----> works fine 
a.some_func()  ----> Error 

libA.A_someFunc(self.obj) 

ValueError异常:程序可能调用的参数太多(超过4个字节)

请帮助。

在此先感谢,

+0

可能的重复[如何使用C++类与ctypes?](http://stackoverflow.com/questions/1615813/how-to-use-c-classes-with-ctypes) – delnan

+0

你忘了'extern“ C“'您使用ctypes的所有功能。恕我直言,'__del__'方法中删除C++对象。 – Arpegius

回答

0

它应该与任何对象创建在Python:

some_var = A() 
+0

实现'__enter__'和'__exit__'可能意味着他想要使用'with var = exr:'语句。 – Arpegius

+0

感谢您的帮助。我意识到我没有在这里粘贴正确的代码。 A级 { public: void someFunc() { } }; // extern“C”//通知编译使用下一个作用域的C-linkage。 // { 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) { delete obj; } – Abhaya

+0

感谢大家帮助。意识到我没有放置正确的代码副本。我要求您重新阅读代码,如果可能的话可以提供帮助。 – Abhaya

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 

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

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

由于上述缓存,请避免在创建库时使用全局加载器实例。您的argtypes,restypeerrcheck函数指针的定义可能会与其他库冲突。请使用CDLL或私人装载机,如cdll = LibraryLoader(CDLL)

此外,cdll.LoadLibrary返回一个非缓存实例CDLL。没有理由直接使用CDLL来代替它。