【问题标题】:"WindowsError: exception: access violation..." - ctypes question“WindowsError:异常:访问冲突...” - ctypes 问题
【发布时间】:2009-09-05 00:35:26
【问题描述】:

这是一个驻留在 DLL 中的 C 函数的原型:

extern "C" void__stdcall__declspec(dllexport) ReturnPulse(double*,double*,double*,double*,double*);

在另一个线程中,我询问了如何正确创建并将必要的参数发送到此函数。

这里是线程: How do I wrap this C function, with multiple arguments, with ctypes?

所以我在上面的线程中使用了很好的信息,但现在我收到了这个错误: WindowsError:异常:访问冲突写入 0x00001001

我不确定如何进行。我使用的是 Windows XP - 如果我登录到管理员帐户,会解决问题吗?或者这是 Python 的内存对象不可变的问题?

谢谢大家!

使用相关 Python 编辑:

FROGPCGPMonitorDLL = windll.LoadLibrary('C:\Program Files\MesaPhotonics\VideoFROG 7.0\PCGPMonitor.dll')

#Function argument:double* pulse
sizePULSE = 2 ##Manual is super unclear here
pulse = c_double * sizePULSE
ptrpulse = pulse()

#Function argument:double* tdl
sizeTRACE = FROGPCGPMonitorDLL.GetSize()
if sizeTRACE == 0 :
    sizeTRACE = 1 #Manually set size to 1 for testing purposes
    print "Size of FROG trace is zero. Probably not right."
tdl = c_double*sizeTRACE
ptrtdl = tdl()


#Function argument:double* tdP
sizeTRACE = FROGPCGPMonitorDLL.GetSize()
if sizeTRACE==0:
    sizeTRACE=1
    print "Size of FROG trace is zero. Probably not right."
tdP = c_double*sizeTRACE
ptrtdP = tdP()


#Function Argument:double* fdl
sizeTRACE = FROGPCGPMonitorDLL.GetSize()
if sizeTRACE==0:
    sizeTRACE=1
    print "Size of FROG trace is zero. Probably not right."
fdl = c_double*sizeTRACE
ptrfdl = fdl()

#Function Argument: double* fdP
sizeTRACE = FROGPCGPMonitorDLL.GetSize()
if sizeTRACE==0:
    sizeTRACE=1
    print "Size of FROG trace is zero. Probably not right."
fdP = c_double*sizeTRACE
ptrfdP = fdP()

FROGPCGPMonitorDLL.ReturnPulse(ptrpulse, ptrtdl, ptrtdP,ptrfdl,ptrfdP)

编辑添加了一些相关代码! 我只是在编写一个简单的脚本来让设备的每个功能首先工作。我知道,变量 sizeTRACE 可以重复使用,但它现在只是测试代码并且设备没有连接,所以 GetSize() 返回零。乘以零会扼杀我的嗡嗡声,所以我现在将其强制为 1。如果不清楚,我很抱歉,并会尝试编辑这篇文章。

第二次编辑: 建议插入设备,看看是否有帮助。我刚刚插入了 FROG,但我仍然遇到同样的错误。很奇怪,我也很无知。无论如何,再次感谢大家!

【问题讨论】:

    标签: python ctypes access-violation windowserror


    【解决方案1】:

    您遇到的错误与管理权限无关。问题是您正在使用 C 并且无意中执行了非法操作(如果不加以检查,这种操作可能会使您的系统崩溃)。

    您收到的错误表明您的程序正在尝试写入内存地址 1001,但不应该写入该内存地址。

    发生这种情况的原因有很多。

    一个可能的原因是您传递给 ReturnPulse 的 double* 没有 ReturnPulse 预期的那么大。您可能至少需要让 GetSize 正常工作......您可以通过分配一个非常大的数组而不是调用 GetSize 来解决它。即

    ptrfdP = (c_double*100000)()
    

    这将分配 100,000 个双打,这可能更适合捕获数字脉冲。

    另一个问题是类型转换可能没有按预期发生。

    如果 ctypes 知道 ReturnPulse 需要五个双指针,您可能会更幸运。即

    # sometime before calling ReturnPulse
    FROGPCGPMonitorDLL.ReturnPulse.argtypes = [POINTER(c_double), POINTER(c_double), POINTER(c_double), POINTER(c_double), POINTER(c_double)]
    

    如果这些技术都不起作用,请将使用文档发送到 ReturnPulse,这将有助于我们识别预期用途。

    或者更好的是,发送应该在 C 中工作的示例代码,我会将其转换为 ctypes 中的等效实现。

    编辑:添加 ReturnPulse 和 ctypes 用法的示例实现。

    我已经实现了类似于我期望 ReturnPulse 在 C DLL 中执行的操作:

    void ReturnPulse(double *a, double*b,double*c,double*d,double*e)
    {
        // write some values to the memory pointed-to by a-e
        // a-e should have enough memory allocated for the loop
        for(int i = 0; i < 20; i++)
        {
            a[i] = 1.0*i;
            b[i] = 3.0*i;
            c[i] = 5.0*i;
            d[i] = 7.0*i;
            e[i] = 13.0*i;
        }
    }
    

    我将它编译成一个 DLL(我称之为examlib),然后使用 ctypes 和以下代码调用它:

    LP_c_double = ctypes.POINTER(ctypes.c_double)
    examlib.ReturnPulse.argtypes = [LP_c_double, LP_c_double, LP_c_double, LP_c_double, LP_c_double, ]
    
    a = (ctypes.c_double*20)()
    b = (ctypes.c_double*20)()
    c = (ctypes.c_double*20)()
    d = (ctypes.c_double*20)()
    e = (ctypes.c_double*20)()
    
    examlib.ReturnPulse(a,b,c,d,e)
    
    print 'values are'
    for array in (a,b,c,d,e):
        print '\t'.join(map(str, array[:5]))
    

    结果输出是

    values are
    0.0     1.0     2.0     3.0     4.0
    0.0     3.0     6.0     9.0     12.0
    0.0     5.0     10.0    15.0    20.0
    0.0     7.0     14.0    21.0    28.0
    0.0     13.0    26.0    39.0    52.0
    

    确实,即使没有设置 ReturnPulse.argtypes,代码也可以正常运行。

    【讨论】:

    • 非常感谢!我会在明天或周五尝试你所说的一切,并尽快让大家知道!
    • 所以我添加了您建议的行 ReturnPulse.argtypes...等,我得到: Traceback(最近一次调用最后一次):文件“C:\Foldershare\Programming\Python\Travis\FROGmoduleTESTv1 \FROGmoduleTEST.py", line 231, in FROGPCGPMonitorDLL.ReturnPulse(ptrpulse, ptrtdl, ptrtdP,ptrfdl,ptrfdP) ArgumentError: argument 1: : expected LP_c_double instance instead of c_double_Array_0_Array_2 我试图也放入一个任意大的双数组,但它给了我同样的 WindowsError。所以我认为 GetSize() 有效!无论如何,感谢迄今为止的帮助。太棒了!
    • 您收到类型错误的事实表明您传递的参数与 ResultPulse 所需的规范不匹配。您正在传递一个 c_double_Array_0_Array_2,它是一个二维双精度数组,宽度为 0,高度为 2。这意味着仍然没有分配适合 ResultPulse 写入的内存。 c_double_Array_0_Array_2 是由 (c_double*0*2)() 创建的,所以我希望您现在测试的代码与问题中包含的代码不同。请记住,ctypes 中的 * 不遵循数学约定。
    • 另外,你应该仔细检查你的调用语义。由于 ResultPulse 是使用 stdcall 调用约定声明的,因此您应该确保使用 WinDLL 加载库...即 FROGPCGPMonitorDLL = ctypes.WinDLL('frogpcgmonitor.dll')
    • 哼。我正在使用windll加载函数,并且我已经设置了argtypes。如果我使用任意大的数组,它会返回相同的访问冲突错误。我现在收到“ArgumentError:argumentError:argument 1::预期的 LP_c_double 实例而不是 c_double_Array_2_Array_64”。我想我在声明数组错误... pulse = c_double * 2 * FROGPCGPMonitorDLL.GetSize() ptrpulse = pulse() 是我在做什么,然后我将它传递给函数。我使用“从 ctypes 导入 *”。这应该是一个指向 c 双精度数组的指针……但它运行不正确。
    【解决方案2】:

    ptrpulse 和朋友是指向各种 ctypes 对象的 python 标识符(我猜它们都是 c_double*2)。它们要么需要用 ctypes 指针对象包装,要么使用 ctypes.byref 传递给 C 函数。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-11-19
      • 2013-03-06
      • 2023-03-14
      • 1970-01-01
      • 2020-06-15
      • 2016-10-24
      • 2019-06-19
      • 2012-05-02
      相关资源
      最近更新 更多