Python ctype:WindowsError:异常:访问冲突读取

Python ctype:WindowsError:异常:访问冲突读取,python,dll,ctypes,windowserror,Python,Dll,Ctypes,Windowserror,我的环境:Windows Vista 64、Python3.1、Visual Studio 2008 sp1 错误说明: 我正在尝试使用ctype包装dll(例如Lib.dll),当继续执行Lib.dll中的函数(例如func())时,出现错误: "WindowsError: exception: access violation reading" 我认为func()与我的.py文件中写入的Lib.dll的以前函数的不同之处在于func()包含双类型参数,但我确信参数传递正确,因为我使用了c\

我的环境:Windows Vista 64、Python3.1、Visual Studio 2008 sp1

错误说明: 我正在尝试使用ctype包装dll(例如Lib.dll),当继续执行Lib.dll中的函数(例如func())时,出现错误:

"WindowsError: exception: access violation reading"
我认为func()与我的.py文件中写入的
Lib.dll
的以前函数的不同之处在于
func()
包含双类型参数,但我确信参数传递正确,因为我使用了
c\u DOUBLE()
来强制转换它。输入
func()
时似乎出现了错误,因为
func()
中的第一个代码
(printf()
)没有执行

我还尝试在C环境中运行相同的dll及其函数,它运行得很顺利

进一步资料:

lib.dll是在MSVC中编译的(外部代码为“C”),我使用CDLL作为调用类型。问题实际上发生在另一个dll(lib2.dll)中的函数上。我只使用LIB DLL,因为LI2.2.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中的函数


谁能给我一些提示吗?感谢< /P> < P> OK,我不能复制这个(Python 2.7.3,Windows 7 X64,Visual C++快件2008)。 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.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; 
}
底部打印的数字
1618402248
是一个垃圾值
ctypes
无法确定函数返回类型,因此它假定它们都返回
int
。在本例中,我们的函数是
void
,因此它不返回任何内容。所看到的返回值是占用
ctypes
认为可能存在返回值的内存位置的情况。通过设置
l1.func.restype=None
,可以告诉
ctypes
此函数的返回类型为
void

<>我不确定你是如何直接调用LI2DLL.DLL中的C++方法的。我尝试过,几乎成功了,但我遇到了一个错误,可能是因为我需要以某种方式传递一个类的实例,但没有这样做:

>l2=CDLL(“Lib2Dll”)
>>>func_int=getattr(l2,“?func_internal@lib2@@QAEXPAD0N@Z")
>>>func_int(“ABC”、“XYZ”、c_double(4.2612))
字符串1:ABC
字符串2:XYZ
双值:4.2612
回溯(最近一次呼叫最后一次):
文件“”,第1行,在
ValueError:调用过程时参数不足(缺少16字节)或调用约定错误

<代码> >代码类型>代码>是C,但您可以编写包装器来公开C++类。自从您提到使用Python3.1以来,我还注意到您有
c\u char\u p('c1')
,其中
'c1'
是一个Unicode字符串。由于提供的示例不是一个完整的示例,无法按原样重现问题,因此很难判断您遇到了什么问题

下面是一个完整的工作示例。您可以通过运行“nmake”从VisualStudio命令提示符构建它

lib1.cpp

此包装器将C++对象“扁平化”为C API。< /P>

#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 lib2.cpp test.py 输出 选择 由于编写包装可能会很乏味,因此最好使用类似于
boost::Python
Cython
SWIG
的东西。我最熟悉SWIG,下面是另一个例子:

生成文件 lib2.i 输出
放一些代码<代码>从ctypes导入*
…以下是我对为什么不能直接调用lib2.dll的猜测:Thx获得回复。我知道在MSVC中编译时,如果没有extern“C”或.def文件,名称将被破坏,func()将变成类似_func@YZ'. 但即使我使用这些(.def等),或者使用'func=getattr(lib2,'_func@YZ顺便说一句,我可以在MSVC的另一个项目中使用loadlibrary()加载lib2.dll而不使用lib2.lib,它可以工作。在调用
func
之前,请尝试
dll.func.argtypes=[c\u char\p,c\u double]
。另外,您的
func
调用有两个
c\u char\p
,但应该只有一个.Thx,非常感谢您为我做这个测试。我直到今天才能够访问我的代码,因为我正在度假。很抱歉这么晚才回复。在lib2.dll中输入my func()时出现的“WindowsError”问题是由于调用旧版本的lib2.dll(dll hell)引起的,我今天才发现。根据您的程序,还应确保问题不是由参数传递引起的。我还删除了func()中的所有参数以检查错误。现在我可以在lib2.dll中输入func(),但我遇到另一个“WindowsError”…我将继续检查新问题。再次感谢您的帮助!谢谢,Mark Tolonen,我认为你的解决方案“扁平化”C++对象是非常聪明的!关于替代方案,在使用ctype之前的几天,我尝试过使用SIP。如果ctype不能满足我的要求,也许我会切换到SIP或SWIG。我曾尝试运行您的示例,但在对makefile使用“nmake”时失败。我输入了msvs2008“命令提示符”并设置了文件的路径(使用cd/d c:\temp),但是我得到了链接错误。我的msvs2008是否有问题,或者我是否需要添加参数,例如libpath?“未解决的外部符号XXX”。我换了一台机器,它工作了。也许我应该重新安装我的msvs2008…很高兴你找到了它。如果答案对你有用,考虑投票和/或接受答案。我重新安装了我的MSVS2008,我成功地通过SIP加载了我的DLL。我希望我能投你的票,但我现在名声不好。无论如何,谢谢你们所有的人!
#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);
}
}
#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);
};
#include <stdio.h>
#include "lib2.h"

void lib2::func(char * c1, char * c2, double d)
{
    printf("%s %s %f\n",c1,c2,d);
}
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.cpp
#!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
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.cpp
%module lib2

%begin %{
#pragma warning(disable:4127 4211 4706)
%}

%{
#include "lib2.h"
%}

%include <windows.i>
%include "lib2.h"
#!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