我的环境: Windows Vista64、Python3.1、Visual Studio2008 sp1
错误描述:我正在尝试包装一个dll (例如。Lib.dll)使用ctype,当继续执行其中一个函数时(例如func())在Lib.dll中出现错误:
"WindowsError: exception: access violation reading"我认为func() ()与之前在我的“.py”文件中编写的Lib.dll函数的不同之处在于,func包含一个双类型参数,但我确信该参数是正确传递的,因为我使用了c_double()对其进行强制转换。似乎在输入func()时出现了错误,因为func()中的第一个代码( (printf())不会执行。
我还试着在C环境下运行同样的dll及其函数,运行流畅。
更多信息:
lib.dll是在MSVC中编译的(带有外部的"C"),我使用CDLL作为调用类型。这个问题实际上发生在另一个dll (lib2.dll)中的函数上。我使用lib.dll只是因为lib2.dll是用C++编写的,并且我用lib2包装了我想要的函数。它看起来是这样的:
///////////////////////////////////
// lib.cpp
lib2 l;
void func(char * c1, char * c2, double d)
{
printf("%s, %s, %f\n", c1, c2, d); // All the parameters are passed correctly
l.func(c1, c2, d); // THIS IS where the error occurred
}
///////////////////////////////////
// lib2.cpp
void lib2::func(char * c1, char * c2, double d)
{
printf(); // The error happened before this line being executed.
...
}
///////////////////////////////////
And python script looks like this:
// my.py
dll = cdll.LoadLibrary("lib.dll")
dll.some_func1(c_char_p('a'))
dll.some_func2(c_char_p('b'))
func(c_char_p('c1'), c_char_p('c2'), c_double(1.1))
////////////////////////////////////同样奇怪的是,当我使用ctype加载lib2.dll时,它不能工作。它显示找不到该函数。所以我必须使用lib.dll来调用lib2.dll中的函数。
有人能给我一些提示吗?谢谢
发布于 2013-04-28 05:54:44
ctypes是用于C的,但是您可以编写一个包装器来公开C++类。既然您提到您使用Python3.1,我还注意到您使用的是c_char_p('c1'),其中'c1'是一个Unicode字符串。由于所提供的示例不是可用于再现问题的完整示例,因此很难判断您遇到了什么问题。
下面是一个完整的工作示例。您可以通过运行"nmake“从Visual Studio命令提示符构建它。
lib1.cpp
此包装器将C++对象“展平”为一个C应用程序接口。
#include "lib2.h"
extern "C" {
__declspec(dllexport) lib2* lib2_new() { return new lib2; }
__declspec(dllexport) void lib2_delete(lib2* p) { delete p; }
__declspec(dllexport) void lib2_func(lib2* p, char* c1, char* c2, double d) {
p->func(c1,c2,d);
}
}lib2.h
#ifdef LIB2_EXPORTS
# define LIB2_API __declspec(dllexport)
#else
# define LIB2_API __declspec(dllimport)
#endif
class LIB2_API lib2
{
public:
void func(char * c1, char * c2, double d);
};lib2.cpp
#include <stdio.h>
#include "lib2.h"
void lib2::func(char * c1, char * c2, double d)
{
printf("%s %s %f\n",c1,c2,d);
}makefile
all: lib1.dll lib2.dll
lib1.dll: lib1.cpp lib2.dll
cl /nologo /LD /W4 lib1.cpp -link lib2.lib
lib2.dll: lib2.cpp lib2.h
cl /nologo /LD /W4 /D LIB2_EXPORTS lib2.cpptest.py
#!python3
from ctypes import *
class lib2:
lib1 = CDLL('lib1')
# It's best to declare all arguments and types, so Python can typecheck.
lib1.lib2_new.argtypes = []
lib1.lib2_new.restype = c_void_p # Can use this for an opaque pointer.
lib1.lib2_func.argtypes = [c_void_p,c_char_p,c_char_p,c_double]
lib1.lib2_func.restype = None
lib1.lib2_delete.argtypes = [c_void_p]
lib1.lib2_delete.restype = None
def __init__(self):
self.obj = self.lib1.lib2_new()
def __del__(self):
self.lib1.lib2_delete(self.obj)
def func(self,c1,c2,d):
self.lib1.lib2_func(self.obj,c1,c2,d)
o = lib2()
o.func(b'abc',b'123',1.2) # Note byte strings输出
C:\temp>nmake
Microsoft (R) Program Maintenance Utility Version 11.00.50727.1
Copyright (C) Microsoft Corporation. All rights reserved.
cl /nologo /LD /W4 /D LIB2_EXPORTS lib2.cpp
lib2.cpp
Creating library lib2.lib and object lib2.exp
cl /nologo /LD /W4 lib1.cpp -link lib2.lib
lib1.cpp
Creating library lib1.lib and object lib1.exp
C:\temp>test.py
abc 123 1.200000替代方案
由于编写包装器可能会很繁琐,因此最好使用boost::Python、Cython或SWIG之类的东西。我最熟悉的是SWIG,下面是另一个例子:
makefile
all: _lib2.pyd lib2.dll
PYTHON_ROOT = c:\python33
lib2_wrap.cxx: lib2.i
@echo Generating wrapper...
swig -c++ -python lib2.i
_lib2.pyd: lib2_wrap.cxx lib2.dll
cl /nologo /EHsc /MD /LD /W4 /I$(PYTHON_ROOT)\include lib2_wrap.cxx -link lib2.lib /LIBPATH:$(PYTHON_ROOT)\libs /OUT:_lib2.pyd
lib2.dll: lib2.cpp lib2.h
cl /nologo /LD /W4 /D LIB2_EXPORTS lib2.cpplib2.i
%module lib2
%begin %{
#pragma warning(disable:4127 4211 4706)
%}
%{
#include "lib2.h"
%}
%include <windows.i>
%include "lib2.h"test.py
#!python3
import lib2
o = lib2.lib2()
o.func('abc','123',1.2) #Note SWIG encodes Unicode strings by default输出
C:\temp>nmake /las
Generating wrapper...
lib2.cpp
Creating library lib2.lib and object lib2.exp
lib2_wrap.cxx
Creating library lib2_wrap.lib and object lib2_wrap.exp
C:\temp>test
abc 123 1.200000发布于 2013-04-28 04:09:11
好吧,我不能重现这个( C++ 2.7.3,Windows7 x64,Visual PythonExpress2008)。
Lib2Dll.h:
#ifdef LIB2DLL_EXPORTS
#define LIB2DLL_API __declspec(dllexport)
#else
#define LIB2DLL_API __declspec(dllimport)
#endif
#include "stdafx.h"
class lib2
{
public:
void LIB2DLL_API func_internal(char *s1, char *s2, double d);
};Lib2Dll.cpp:
#include "stdafx.h"
#include "Lib2Dll.h"
#include <iostream>
using namespace std;
void lib2::func_internal(char *s1, char *s2, double d)
{
cout << "String 1: " << s1 << endl << "String 2: " << s2 << endl << "Double value: " << d << endl;
}Lib1Dll.h:
#ifdef LIB1DLL_EXPORTS
#define LIB1DLL_API __declspec(dllexport)
#else
#define LIB1DLL_API __declspec(dllimport)
#endif
#include "stdafx.h"
#include "Lib2Dll.h"
extern "C" {
void LIB1DLL_API func(char *s1, char *s2, double d);
}Lib1Dll.cpp:
#include "stdafx.h"
#include "Lib1Dll.h"
#include <iostream>
using namespace std;
lib2 l;
void func(char *s1, char *s2, double d)
{
cout << "Before" << endl;
l.func_internal(s1, s2, d);
cout << "After" << endl;
}在VC++ 2008解决方案中有两个项目,Lib2Dll (包含Lib2Dll.h和Lib2Dll.cpp)和Lib1Dll (包含Lib1Dll.h和Lib1Dll.cpp)。Lib1Dll依赖于Lib2Dll。这两个库都设置为使用cdecl调用约定。
我编译了解决方案,它生成了Lib1Dll.dll和Lib2Dll.dll。然后我尝试在Python中使用这些库:
Python 2.7.3 (default, Apr 10 2012, 23:31:26) [MSC v.1500 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> from ctypes import CDLL, c_double
>>> l1 = CDLL("Lib1Dll")
>>> l1.func("ABC", "XYZ", c_double(3.2463))
Before
String 1: ABC
String 2: XYZ
Double value: 3.2463
After
1618402248底部打印出来的数字1618402248是一个垃圾值。ctypes不能确定函数返回类型,所以它假定它们都返回int。在本例中,我们的函数是void,所以它不会返回任何内容。所看到的返回值是占用ctypes认为返回值可能所在的内存位置发生的任何事情。您可以通过设置l1.func.restype = None来告诉ctypes此函数的返回类型为void。
我不确定如何在Lib2Dll.dll中直接调用C++方法。我试过了,它几乎可以工作,但我得到了一个错误,可能是因为我需要以某种方式传递一个类的实例,但没有这样做:
>>> l2 = CDLL("Lib2Dll")
>>> func_int = getattr(l2, "?func_internal@lib2@@QAEXPAD0N@Z")
>>> func_int("ABC", "XYZ", c_double(4.2612))
String 1: ABC
String 2: XYZ
Double value: 4.2612
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: Procedure called with not enough arguments (16 bytes missing) or wrong calling conventionhttps://stackoverflow.com/questions/16249752
复制相似问题