使用Cython包装c ++ api时的“访问冲突读取位置”

时间:2014-11-06 11:03:25

标签: python c++ c dll cython

我正在用Python编写一个包装模块,用于用c ++编写的api。 api本身是一个c library / api的包装器,用于在我的计算机上本地安装的Windows(7)应用程序。我可以访问c ++ api源代码而不是c库。我在Python 2.7.5(即VS 9.0)中使用distutils构建了Cython模块,并且在32位安装中也尝试了3.4.1(即VS 10.0)。

访问该模块时会发生一个弹出窗口,表示python.exe has stopped working然后Process finished with exit code -1073741819 (0xC0000005)按下关闭时会发生这种情况。在调试时(我有Visual Studio 2012),我得到:Unhandled exception at 0x64ED1EB2 (apiclient10m.dll) in python.exe: 0xC0000005: Access violation reading location 0x7C03B776。我有时会得到Unhandled exception at 0x1E0EFECF (python27.dll) in python.exe: 0xC0000005: Access violation writing location 0x5753422C.取决于我如何称呼api。

我认为它与一个对象“ObjStruct”有关,该对象在c ++ api中定义并发送到c库进行更新。然后在c ++中读取该对象,并将int发送回Cython。返回某些内存位置时调用堆栈中的某个位置是不允许的访问。

这就是它的样子:

mymodule.pyx:

# distutils: language = c++
# distutils: extra_compile_args = ["/EHsc"]
# distutils: sources = [connection.cpp, object.cpp]
# distutils: include_dirs=['C:\\Program Files (x86)\\App\\api']
# distutils: library_dirs=['C:\\Program Files (x86)\\App\\api']

from libcpp.string cimport string
from cython.operator cimport dereference as deref

cdef extern from "connection.h" namespace "pvcs":

    cdef cppclass connection:
        connection() except +
        ...

cdef class PyConnection:

    cdef connection *_cpp_connection_instance    # Pointer to wrapped connection instance

    def __cinit__(self):
        self._cpp_connection_instance = new connection()

    def __dealloc__(self):
        del self._cpp_connection_instance

cdef extern from "object.h" namespace "pvcs":

    cdef int get_baseline_uid(connection c, string spec)

def get_uid(PyConnection connection, bytes specification):
    return get_baseline_uid(
        deref(connection._cpp_connection_instance), specification)

get_uid方法是失败的方法。

c ++ api:

namespace pvcs {
  class connection {
    public:
      connection();
      ~connection();

  int get_baseline_uid(connection & c, std::string & spec) {
    ObjStruct os = { 0 };

    //Fills the struct os with the information
    if(InitSpec(c.uid(), const_cast<char *>(spec.c_str()), BASELINE, &os) == 1) {
      int uid = os.uid;
      ObjFree(&os);
      return uid;  // Somewhere after this point the error occurs.
    }
    return -1;
  }

连接部分在显示用于登录应用程序的窗口的情况下正常工作。这是失败的get_baseline_uid。 c api h-file的一部分:

typedef struct ObjStruct
{
    int         uid;
    int         objType;
    int         typeUid;
    _TCHAR      typeName[(L_TYPE_NAME + 1)*CHARSIZEMAX];
    _TCHAR      productId[(L_PRODUCT_ID + 1)*CHARSIZEMAX];
    _TCHAR      objId[(MAX_L_ID + 1)*CHARSIZEMAX];
    _TCHAR      variant[(L_VARIANT + 1)*CHARSIZEMAX];
    _TCHAR      revision[(L_REVISION + 1)*CHARSIZEMAX];
    _TCHAR      description[(L_DESCRIPTION + 1)*CHARSIZEMAX];
    _TCHAR      userName[(L_USER + 1)*CHARSIZEMAX];
    _TCHAR      status[(L_STATUS + 1)*CHARSIZEMAX];
    _TCHAR      dateTime[(L_DATE_TIME + 1)*CHARSIZEMAX];
    _TCHAR      isExtracted;
    int         noAttrs;        /* The number of attributes for this object. */
    ObjAttrStruct *attrs;   /* Pointer to the array of attributes. */
    int         specUid;
}   ObjStruct;

extern int APIFUN CCONV InitSpec(int, _TCHAR*, int, PcmsObjStruct*);

h文件驻留在指定给distutils C:\Program Files (x86)\App\api的目录中,还有一堆静态库(.lib-files)。这些库似乎访问C:\Program Files (x86)\App\prog文件夹中的dll文件。这是导致访问冲突的dll apiclient10m.dll的位置。

distutils setup.py:

from distutils.core import setup
from Cython.Build import cythonize

METADATA = {'name': 'mymodule', 
            'ext_modules': cythonize("mymodule.pyx"),}

if __name__ == '__main__':
    metadata = METADATA.copy()
    setup(**metadata)

所有内容都可以编译和链接,但在运行时例如根据我上面解释的内容,它在最后一行失败了:

import mymodule
con = mymodule.PyConnection()
uid = mymodule.get_uid(con, "item specification")

0 个答案:

没有答案