我正在用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")