Python ctypes:如何使用传递给DLL的指针?

时间:2018-01-03 02:08:29

标签: python ctypes

使用ctypes,我在Python中创建一个数组以传递给ctypes.WinDLL:

arrA = (ctypes.c_float * len(varA))(*varA)

然后我将指向数组的指针传递给DLL:

retvar = SimpleTest(ctypes.byref(pvarr),ctypes.byref(pvarr2))

pvarr 的第一个元素是指向数组 arrA 的指针。

但是当我尝试写入数组 arrA 的值(使用传递的指针)时,我得到“对内存位置的无效访问”。

所以我的问题是:我现在如何使用指向Python中创建的ctypes.c_float数组的指针并传递给DLL?这不可能吗?

经过一段时间的努力,我已经解决了这个问题。上面显示的数组是不可变的;要传递一个可变数组,我们这样做:

OutputArrayType = ctypes.c_float * 1000
arrNew = OutputArrayType()

ctypes数组类型是一个类,因此要使用它,我们必须创建一个类实例(arrayNew)。

但是当我通过引用传递它的指针时:

retvar = SimpleTest(ctypes.byref(PVarrNew),ctypes.byref(arrNew))

指针值是与id(arrayNew)不同的数字。即便如此,DLL仍然无法访问任何一个指针中的任何值,因为我得到“无效访问内存”。

所以现在我的问题是:为什么ctypes.byref(arrNew)传递的指针与id(arrNew)不同。

马克,谢谢你的回复。以下是简明摘要:

第一个数组不可变,它为每个赋值创建一个新对象;我通过在作业之前和之后检查其id()来确认。但是,实例化为类的第二个数组是可变的,这就是我使用它的原因。

所以我创建了数组:

OutputArrayType = ctypes.c_int64 * 1000
arrNew = OutputArrayType()

并调用DLL:

retvar = SimpleTest(ctypes.byref(PVarrNew),ctypes.byref(arrNew))

在64位汇编程序中,第二个参数(指向 arrNew 的指针)在rdx中传递。所以在NASM中,我可以用两种不同的方式写入这个数组,但都返回“无效访问内存位置。”

mov rdi,rdx
mov rax,1534
mov [rdi+8],rax
push qword [rax]
pop qword [rdx+32]

如果我在调用DLL(其中指向数组的指针位于rcx中)中反转数组的顺序,则会发生同样的情况。

但是,我可以从数组中读取,但我无法写入。

非常感谢你的帮助。

1 个答案:

答案 0 :(得分:1)

你的两个例子都是可变的。你提到了一个赋值,它总是创建一个新对象,但没有一个例子......:^)这就是我对可重现的例子的意思。使用适当的Python编译32位或64位的作品:

test.c (使用Microsoft编译器的Windows示例)

#include <stdio.h>
__declspec(dllexport) void __stdcall SimpleTest(float* array, int length)
{
    int i;
    for(i = 0; i < length; ++i)
    {
        printf("array[%d] = %f\n",i,array[i]);
        array[i] *= 2;
    }
}

test.py (可在Python 2和3之间移植)

from __future__ import print_function
from ctypes import *
varA = [1.2,2.5,3.5]
arr = (c_float * len(varA))(*varA)  # 1st example
print(id(arr))
arr[0] = 1.5 # mutate array
print(id(arr))

arrType = c_float * 10    # 2nd example
arrInstance = arrType()
print(id(arrInstance))
arrInstance[0] = 1.5 # mutate array
print(id(arrInstance))

dll = WinDLL('test')
print(list(arr))
dll.SimpleTest(arr,len(arr)) # Passing the array to C and changing it
print(list(arr))

输出(32-和64-相同,但ID不同,请注意ID在变异后不会改变)

2610964912456
2610964912456
2610964912968
2610964912968
[1.5, 2.5, 3.5]
array[0] = 1.500000
array[1] = 2.500000
array[2] = 3.500000
[3.0, 5.0, 7.0]